Generate sine waves with 2 mbeds synchronised. Configurable amplitude and phase. Built for 50 Hz mains simulations.

Dependencies:   MODDMA mbed

Description

Small program based on the MODDMA buffered sine wave example.

This programs reads pin 22 to operate in Master (low) or Slave mode. Then configures pin 21 as output (master) or input (slave), in master mode led2 is on. Use a resistor (100 ohm) between the pin21's of master to slave.

The program then calculates a buffer of sine waves for the DMA with parameters given. And starts the DMA and DAC to generate the sine.

On the callbacks of the dma complete (there are 2) slave waits for a sync and master gives a sync, p21. Master waits a few extra clocks to make sure slave is ready.

Commands can be given over Serial port to modify the parameters on the run. Frequency can be changed for master and slave, but it is better to keep the same. Use "f xx.xx". Phase can be changed for master and slave Amplitude can be changed for master and slave.

Hookup

  • Wire p22 high or low.
  • Serial sr(p9,p10) from master to slave.
  • Wire trigger p21 to p21.
  • Output p18 (analogout)

Information

Do not forget a small RC filter on the DAC output.

Master Commands

<master/slave/frequency> <frequency/phase/amplitude> <space> <number> <line feed>

Example commands for serial:

  • master frequency 50.1 hz
    • mf 50.1\n
  • frequency 50.1 Hz
    • f 50.1\n
  • master phase 3.1415 (or 1.0)
    • mp 1\n
  • slave phase 1.5 pi
    • sp 1.5\n

Or use this GUI

https://dl.dropboxusercontent.com/s/uvwsroyu41vzkwg/2013-06-19%2010_35_52-WaveSim.png

Download, or Download C# Code (Visual Studio 2010)

Committer:
jeroen3
Date:
Thu May 30 21:04:43 2013 +0000
Revision:
0:46bb6ad79423
Child:
1:b97d61d415ff
Basics; Double mbed synchronised 50 Hz generator (with dma)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jeroen3 0:46bb6ad79423 1 /*
jeroen3 0:46bb6ad79423 2 * Demonstrates sending a buffer repeatedly to the DAC using DMA.
jeroen3 0:46bb6ad79423 3 * Connect an oscilloscope to Mbed pin 18. This example doesn't
jeroen3 0:46bb6ad79423 4 * output anything else (nothing on any serial ports).
jeroen3 0:46bb6ad79423 5 */
jeroen3 0:46bb6ad79423 6 #include "mbed.h"
jeroen3 0:46bb6ad79423 7 #include "MODDMA.h"
jeroen3 0:46bb6ad79423 8 #include <cmath>
jeroen3 0:46bb6ad79423 9
jeroen3 0:46bb6ad79423 10 Serial pc(USBTX, USBRX);
jeroen3 0:46bb6ad79423 11
jeroen3 0:46bb6ad79423 12 const double PI = 3.141592653589793238462;
jeroen3 0:46bb6ad79423 13 const float PI_F = 3.14159265358979f;
jeroen3 0:46bb6ad79423 14
jeroen3 0:46bb6ad79423 15 // Make the buffer size match the number of degrees
jeroen3 0:46bb6ad79423 16 // in a circle since we are going to output a sinewave.
jeroen3 0:46bb6ad79423 17 #define BUFFER_SIZE 360
jeroen3 0:46bb6ad79423 18
jeroen3 0:46bb6ad79423 19 // Set DAC output power mode.
jeroen3 0:46bb6ad79423 20 #define DAC_POWER_MODE (1 << 16)
jeroen3 0:46bb6ad79423 21
jeroen3 0:46bb6ad79423 22 DigitalOut led1(LED1);
jeroen3 0:46bb6ad79423 23 DigitalOut led2(LED2);
jeroen3 0:46bb6ad79423 24 DigitalOut led3(LED3);
jeroen3 0:46bb6ad79423 25 DigitalOut led4(LED4);
jeroen3 0:46bb6ad79423 26 DigitalIn modesel(p22);
jeroen3 0:46bb6ad79423 27 DigitalInOut trigger(p21);
jeroen3 0:46bb6ad79423 28
jeroen3 0:46bb6ad79423 29 DigitalOut timetest(p23);
jeroen3 0:46bb6ad79423 30
jeroen3 0:46bb6ad79423 31 int buffer[2][BUFFER_SIZE];
jeroen3 0:46bb6ad79423 32
jeroen3 0:46bb6ad79423 33 typedef enum {MASTER, SLAVE} modesel_t;
jeroen3 0:46bb6ad79423 34 modesel_t mode;
jeroen3 0:46bb6ad79423 35
jeroen3 0:46bb6ad79423 36 AnalogOut signal(p18);
jeroen3 0:46bb6ad79423 37
jeroen3 0:46bb6ad79423 38 MODDMA dma;
jeroen3 0:46bb6ad79423 39 MODDMA_Config *conf0, *conf1;
jeroen3 0:46bb6ad79423 40
jeroen3 0:46bb6ad79423 41 void TC0_callback(void);
jeroen3 0:46bb6ad79423 42 void ERR0_callback(void);
jeroen3 0:46bb6ad79423 43
jeroen3 0:46bb6ad79423 44 void TC1_callback(void);
jeroen3 0:46bb6ad79423 45 void ERR1_callback(void);
jeroen3 0:46bb6ad79423 46
jeroen3 0:46bb6ad79423 47 // Config phase (2*pi is one period)
jeroen3 0:46bb6ad79423 48 double phase_master = PI * 0;
jeroen3 0:46bb6ad79423 49 double phase_slave = PI * 0;
jeroen3 0:46bb6ad79423 50 // Config amplitude, x * 3.3 Volt
jeroen3 0:46bb6ad79423 51 double amplitude_master = 1;
jeroen3 0:46bb6ad79423 52 double amplitude_slave = 0.5;
jeroen3 0:46bb6ad79423 53
jeroen3 0:46bb6ad79423 54 void wait_for_sync(){
jeroen3 0:46bb6ad79423 55 switch(mode){
jeroen3 0:46bb6ad79423 56 case MASTER:
jeroen3 0:46bb6ad79423 57 // Wait a few clocks to make sure slave is waiting
jeroen3 0:46bb6ad79423 58 for(uint32_t i=0; i<10; i++){ __NOP(); __NOP(); __NOP(); __NOP(); }
jeroen3 0:46bb6ad79423 59 // Trigger toggle
jeroen3 0:46bb6ad79423 60 LPC_GPIO2->FIOPIN ^= (1<<5);
jeroen3 0:46bb6ad79423 61 break;
jeroen3 0:46bb6ad79423 62 case SLAVE:
jeroen3 0:46bb6ad79423 63 // Wait for pinchange
jeroen3 0:46bb6ad79423 64 {
jeroen3 0:46bb6ad79423 65 uint32_t pinstate = trigger;
jeroen3 0:46bb6ad79423 66 while( pinstate == trigger);
jeroen3 0:46bb6ad79423 67 }
jeroen3 0:46bb6ad79423 68 break;
jeroen3 0:46bb6ad79423 69 }
jeroen3 0:46bb6ad79423 70 }
jeroen3 0:46bb6ad79423 71
jeroen3 0:46bb6ad79423 72 void calculate_sines(){
jeroen3 0:46bb6ad79423 73 // Create a sinewave buffer for testing.
jeroen3 0:46bb6ad79423 74 switch(mode){
jeroen3 0:46bb6ad79423 75 case MASTER:
jeroen3 0:46bb6ad79423 76 for (int i = 0; i <= 360; i++) buffer[0][i] = amplitude_master * (512 * sin((3.14159/180.0 * i) + phase_master)) + 512;
jeroen3 0:46bb6ad79423 77 break;
jeroen3 0:46bb6ad79423 78 case SLAVE:
jeroen3 0:46bb6ad79423 79 for (int i = 0; i <= 360; i++) buffer[0][i] = amplitude_slave * (512 * sin((3.14159/180.0 * i) + phase_slave)) + 512;
jeroen3 0:46bb6ad79423 80 break;
jeroen3 0:46bb6ad79423 81 }
jeroen3 0:46bb6ad79423 82
jeroen3 0:46bb6ad79423 83 // Adjust the sinewave buffer for use with DAC hardware.
jeroen3 0:46bb6ad79423 84 for (int i = 0; i < 360; i++) {
jeroen3 0:46bb6ad79423 85 buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0);
jeroen3 0:46bb6ad79423 86 buffer[1][i] = buffer[0][i]; // Just create a copy of buffer0 to continue sinewave.
jeroen3 0:46bb6ad79423 87 }
jeroen3 0:46bb6ad79423 88 }
jeroen3 0:46bb6ad79423 89
jeroen3 0:46bb6ad79423 90 int main() {
jeroen3 0:46bb6ad79423 91 volatile int life_counter = 0;
jeroen3 0:46bb6ad79423 92 pc.baud(115200);
jeroen3 0:46bb6ad79423 93 timetest = 0;
jeroen3 0:46bb6ad79423 94
jeroen3 0:46bb6ad79423 95 if(modesel == 1){
jeroen3 0:46bb6ad79423 96 pc.printf("slave\r\n");
jeroen3 0:46bb6ad79423 97 trigger.input();
jeroen3 0:46bb6ad79423 98 mode = SLAVE;
jeroen3 0:46bb6ad79423 99 led2 = 0;
jeroen3 0:46bb6ad79423 100 }else{
jeroen3 0:46bb6ad79423 101 pc.printf("master\r\n");
jeroen3 0:46bb6ad79423 102 trigger.output();
jeroen3 0:46bb6ad79423 103 led2 = 1;
jeroen3 0:46bb6ad79423 104 mode = MASTER;
jeroen3 0:46bb6ad79423 105 }
jeroen3 0:46bb6ad79423 106
jeroen3 0:46bb6ad79423 107 calculate_sines();
jeroen3 0:46bb6ad79423 108
jeroen3 0:46bb6ad79423 109 // Prepare the GPDMA system for buffer0.
jeroen3 0:46bb6ad79423 110 conf0 = new MODDMA_Config;
jeroen3 0:46bb6ad79423 111 conf0
jeroen3 0:46bb6ad79423 112 ->channelNum ( MODDMA::Channel_0 )
jeroen3 0:46bb6ad79423 113 ->srcMemAddr ( (uint32_t) &buffer[0] )
jeroen3 0:46bb6ad79423 114 ->dstMemAddr ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 115 ->transferSize ( 360 )
jeroen3 0:46bb6ad79423 116 ->transferType ( MODDMA::m2p )
jeroen3 0:46bb6ad79423 117 ->dstConn ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 118 ->attach_tc ( &TC0_callback )
jeroen3 0:46bb6ad79423 119 ->attach_err ( &ERR0_callback )
jeroen3 0:46bb6ad79423 120 ; // config end
jeroen3 0:46bb6ad79423 121
jeroen3 0:46bb6ad79423 122
jeroen3 0:46bb6ad79423 123 // Prepare the GPDMA system for buffer1.
jeroen3 0:46bb6ad79423 124 conf1 = new MODDMA_Config;
jeroen3 0:46bb6ad79423 125 conf1
jeroen3 0:46bb6ad79423 126 ->channelNum ( MODDMA::Channel_1 )
jeroen3 0:46bb6ad79423 127 ->srcMemAddr ( (uint32_t) &buffer[1] )
jeroen3 0:46bb6ad79423 128 ->dstMemAddr ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 129 ->transferSize ( 360 )
jeroen3 0:46bb6ad79423 130 ->transferType ( MODDMA::m2p )
jeroen3 0:46bb6ad79423 131 ->dstConn ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 132 ->attach_tc ( &TC1_callback )
jeroen3 0:46bb6ad79423 133 ->attach_err ( &ERR1_callback )
jeroen3 0:46bb6ad79423 134 ; // config end
jeroen3 0:46bb6ad79423 135
jeroen3 0:46bb6ad79423 136
jeroen3 0:46bb6ad79423 137 // Calculating the transfer frequency:
jeroen3 0:46bb6ad79423 138 // By default, the Mbed library sets the PCLK_DAC clock value
jeroen3 0:46bb6ad79423 139 // to 24MHz. One complete sinewave cycle in each buffer is 360
jeroen3 0:46bb6ad79423 140 // points long. So, for a 1Hz wave we would need to transfer 360
jeroen3 0:46bb6ad79423 141 // values per second. That would be 24000000/360 which is approx
jeroen3 0:46bb6ad79423 142 // 66,666. But that's no good! The count val is only 16bits in size
jeroen3 0:46bb6ad79423 143 // so bare this in mind. If you need to go slower you will need to
jeroen3 0:46bb6ad79423 144 // alter PCLK_DAC from CCLK/4 to CCLK/8.
jeroen3 0:46bb6ad79423 145 // For our demo we are going to have the sinewave run at 1kHz.
jeroen3 0:46bb6ad79423 146 // That's 24000000/360000 which is approx 66. Experimentation
jeroen3 0:46bb6ad79423 147 // however showed 65 to get closer to 1kHz (on my Mbed and scope
jeroen3 0:46bb6ad79423 148 // at least).
jeroen3 0:46bb6ad79423 149 const double dacclk = 24000000;
jeroen3 0:46bb6ad79423 150 const double dacper = dacclk / 360;
jeroen3 0:46bb6ad79423 151 double wavefreq = 50;
jeroen3 0:46bb6ad79423 152 double ddacdiv = dacper / (wavefreq);
jeroen3 0:46bb6ad79423 153 unsigned int dacdiv = ddacdiv;
jeroen3 0:46bb6ad79423 154 pc.printf("dacdiv set to: %d\r\n",dacdiv);
jeroen3 0:46bb6ad79423 155 LPC_DAC->DACCNTVAL = dacdiv; // 6500 for 10Hz
jeroen3 0:46bb6ad79423 156
jeroen3 0:46bb6ad79423 157 // Prepare first configuration.
jeroen3 0:46bb6ad79423 158 if (!dma.Prepare( conf0 )) {
jeroen3 0:46bb6ad79423 159 error("Doh!");
jeroen3 0:46bb6ad79423 160 }
jeroen3 0:46bb6ad79423 161
jeroen3 0:46bb6ad79423 162 if(mode == MASTER){
jeroen3 0:46bb6ad79423 163 wait(0.1);
jeroen3 0:46bb6ad79423 164 }
jeroen3 0:46bb6ad79423 165 wait_for_sync();
jeroen3 0:46bb6ad79423 166
jeroen3 0:46bb6ad79423 167 // Begin (enable DMA and counter). Note, don't enable
jeroen3 0:46bb6ad79423 168 // DBLBUF_ENA as we are using DMA double buffering.
jeroen3 0:46bb6ad79423 169 LPC_DAC->DACCTRL |= (3UL << 2);
jeroen3 0:46bb6ad79423 170
jeroen3 0:46bb6ad79423 171 while (1) {
jeroen3 0:46bb6ad79423 172 // There's not a lot to do as DMA and interrupts are
jeroen3 0:46bb6ad79423 173 // now handling the buffer transfers. So we'll just
jeroen3 0:46bb6ad79423 174 // flash led1 to show the Mbed is alive and kicking.
jeroen3 0:46bb6ad79423 175 if (life_counter++ > 1000000) {
jeroen3 0:46bb6ad79423 176 led1 = !led1; // Show some sort of life.
jeroen3 0:46bb6ad79423 177 life_counter = 0;
jeroen3 0:46bb6ad79423 178 }
jeroen3 0:46bb6ad79423 179 }
jeroen3 0:46bb6ad79423 180 }
jeroen3 0:46bb6ad79423 181
jeroen3 0:46bb6ad79423 182 // Configuration callback on TC
jeroen3 0:46bb6ad79423 183 void TC0_callback(void) {
jeroen3 0:46bb6ad79423 184
jeroen3 0:46bb6ad79423 185
jeroen3 0:46bb6ad79423 186 // Just show sending buffer0 complete.
jeroen3 0:46bb6ad79423 187 led3 = !led3;
jeroen3 0:46bb6ad79423 188
jeroen3 0:46bb6ad79423 189 // Implement wait for trigger if slave mode
jeroen3 0:46bb6ad79423 190 wait_for_sync();
jeroen3 0:46bb6ad79423 191
jeroen3 0:46bb6ad79423 192 // Get configuration pointer.
jeroen3 0:46bb6ad79423 193 MODDMA_Config *config = dma.getConfig();
jeroen3 0:46bb6ad79423 194
jeroen3 0:46bb6ad79423 195 // Finish the DMA cycle by shutting down the channel.
jeroen3 0:46bb6ad79423 196 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
jeroen3 0:46bb6ad79423 197
jeroen3 0:46bb6ad79423 198 // Swap to buffer1
jeroen3 0:46bb6ad79423 199 dma.Prepare( conf1 );
jeroen3 0:46bb6ad79423 200
jeroen3 0:46bb6ad79423 201 // Clear DMA IRQ flags.
jeroen3 0:46bb6ad79423 202 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
jeroen3 0:46bb6ad79423 203 }
jeroen3 0:46bb6ad79423 204
jeroen3 0:46bb6ad79423 205 // Configuration callback on Error
jeroen3 0:46bb6ad79423 206 void ERR0_callback(void) {
jeroen3 0:46bb6ad79423 207 error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
jeroen3 0:46bb6ad79423 208 }
jeroen3 0:46bb6ad79423 209
jeroen3 0:46bb6ad79423 210 // Configuration callback on TC
jeroen3 0:46bb6ad79423 211 void TC1_callback(void) {
jeroen3 0:46bb6ad79423 212
jeroen3 0:46bb6ad79423 213 // Just show sending buffer1 complete.
jeroen3 0:46bb6ad79423 214 led4 = !led4;
jeroen3 0:46bb6ad79423 215
jeroen3 0:46bb6ad79423 216 // Implement wait for trigger if slave mode
jeroen3 0:46bb6ad79423 217 wait_for_sync();
jeroen3 0:46bb6ad79423 218
jeroen3 0:46bb6ad79423 219 // Get configuration pointer.
jeroen3 0:46bb6ad79423 220 MODDMA_Config *config = dma.getConfig();
jeroen3 0:46bb6ad79423 221
jeroen3 0:46bb6ad79423 222 // Finish the DMA cycle by shutting down the channel.
jeroen3 0:46bb6ad79423 223 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
jeroen3 0:46bb6ad79423 224
jeroen3 0:46bb6ad79423 225 // Swap to buffer0
jeroen3 0:46bb6ad79423 226 dma.Prepare( conf0 );
jeroen3 0:46bb6ad79423 227
jeroen3 0:46bb6ad79423 228 // Clear DMA IRQ flags.
jeroen3 0:46bb6ad79423 229 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
jeroen3 0:46bb6ad79423 230 }
jeroen3 0:46bb6ad79423 231
jeroen3 0:46bb6ad79423 232 // Configuration callback on Error
jeroen3 0:46bb6ad79423 233 void ERR1_callback(void) {
jeroen3 0:46bb6ad79423 234 error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
jeroen3 0:46bb6ad79423 235 }