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:24:35 2013 +0000
Revision:
1:b97d61d415ff
Parent:
0:46bb6ad79423
Child:
2:edd6401d9aa0
Added frequency to parameters

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 1:b97d61d415ff 51 double amplitude_master = 1;
jeroen3 1:b97d61d415ff 52 double amplitude_slave = 0.5;
jeroen3 1:b97d61d415ff 53 // Config frequency, (if using synchronisation these must be identical)
jeroen3 1:b97d61d415ff 54 double freq_master = 50;
jeroen3 1:b97d61d415ff 55 double freq_slave = freq_master;
jeroen3 0:46bb6ad79423 56
jeroen3 1:b97d61d415ff 57 // Sync function
jeroen3 0:46bb6ad79423 58 void wait_for_sync(){
jeroen3 0:46bb6ad79423 59 switch(mode){
jeroen3 0:46bb6ad79423 60 case MASTER:
jeroen3 0:46bb6ad79423 61 // Wait a few clocks to make sure slave is waiting
jeroen3 0:46bb6ad79423 62 for(uint32_t i=0; i<10; i++){ __NOP(); __NOP(); __NOP(); __NOP(); }
jeroen3 0:46bb6ad79423 63 // Trigger toggle
jeroen3 0:46bb6ad79423 64 LPC_GPIO2->FIOPIN ^= (1<<5);
jeroen3 0:46bb6ad79423 65 break;
jeroen3 0:46bb6ad79423 66 case SLAVE:
jeroen3 0:46bb6ad79423 67 // Wait for pinchange
jeroen3 0:46bb6ad79423 68 {
jeroen3 0:46bb6ad79423 69 uint32_t pinstate = trigger;
jeroen3 0:46bb6ad79423 70 while( pinstate == trigger);
jeroen3 0:46bb6ad79423 71 }
jeroen3 0:46bb6ad79423 72 break;
jeroen3 0:46bb6ad79423 73 }
jeroen3 0:46bb6ad79423 74 }
jeroen3 0:46bb6ad79423 75
jeroen3 1:b97d61d415ff 76 // Calculate function
jeroen3 0:46bb6ad79423 77 void calculate_sines(){
jeroen3 0:46bb6ad79423 78 // Create a sinewave buffer for testing.
jeroen3 0:46bb6ad79423 79 switch(mode){
jeroen3 0:46bb6ad79423 80 case MASTER:
jeroen3 0:46bb6ad79423 81 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 82 break;
jeroen3 0:46bb6ad79423 83 case SLAVE:
jeroen3 0:46bb6ad79423 84 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 85 break;
jeroen3 0:46bb6ad79423 86 }
jeroen3 0:46bb6ad79423 87
jeroen3 0:46bb6ad79423 88 // Adjust the sinewave buffer for use with DAC hardware.
jeroen3 0:46bb6ad79423 89 for (int i = 0; i < 360; i++) {
jeroen3 0:46bb6ad79423 90 buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0);
jeroen3 0:46bb6ad79423 91 buffer[1][i] = buffer[0][i]; // Just create a copy of buffer0 to continue sinewave.
jeroen3 0:46bb6ad79423 92 }
jeroen3 0:46bb6ad79423 93 }
jeroen3 0:46bb6ad79423 94
jeroen3 1:b97d61d415ff 95 // Main
jeroen3 0:46bb6ad79423 96 int main() {
jeroen3 0:46bb6ad79423 97 volatile int life_counter = 0;
jeroen3 0:46bb6ad79423 98 pc.baud(115200);
jeroen3 0:46bb6ad79423 99 timetest = 0;
jeroen3 0:46bb6ad79423 100
jeroen3 0:46bb6ad79423 101 if(modesel == 1){
jeroen3 0:46bb6ad79423 102 pc.printf("slave\r\n");
jeroen3 0:46bb6ad79423 103 trigger.input();
jeroen3 0:46bb6ad79423 104 mode = SLAVE;
jeroen3 0:46bb6ad79423 105 led2 = 0;
jeroen3 0:46bb6ad79423 106 }else{
jeroen3 0:46bb6ad79423 107 pc.printf("master\r\n");
jeroen3 0:46bb6ad79423 108 trigger.output();
jeroen3 0:46bb6ad79423 109 led2 = 1;
jeroen3 0:46bb6ad79423 110 mode = MASTER;
jeroen3 0:46bb6ad79423 111 }
jeroen3 0:46bb6ad79423 112
jeroen3 0:46bb6ad79423 113 calculate_sines();
jeroen3 0:46bb6ad79423 114
jeroen3 0:46bb6ad79423 115 // Prepare the GPDMA system for buffer0.
jeroen3 0:46bb6ad79423 116 conf0 = new MODDMA_Config;
jeroen3 0:46bb6ad79423 117 conf0
jeroen3 0:46bb6ad79423 118 ->channelNum ( MODDMA::Channel_0 )
jeroen3 0:46bb6ad79423 119 ->srcMemAddr ( (uint32_t) &buffer[0] )
jeroen3 0:46bb6ad79423 120 ->dstMemAddr ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 121 ->transferSize ( 360 )
jeroen3 0:46bb6ad79423 122 ->transferType ( MODDMA::m2p )
jeroen3 0:46bb6ad79423 123 ->dstConn ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 124 ->attach_tc ( &TC0_callback )
jeroen3 0:46bb6ad79423 125 ->attach_err ( &ERR0_callback )
jeroen3 0:46bb6ad79423 126 ; // config end
jeroen3 0:46bb6ad79423 127
jeroen3 0:46bb6ad79423 128
jeroen3 0:46bb6ad79423 129 // Prepare the GPDMA system for buffer1.
jeroen3 0:46bb6ad79423 130 conf1 = new MODDMA_Config;
jeroen3 0:46bb6ad79423 131 conf1
jeroen3 0:46bb6ad79423 132 ->channelNum ( MODDMA::Channel_1 )
jeroen3 0:46bb6ad79423 133 ->srcMemAddr ( (uint32_t) &buffer[1] )
jeroen3 0:46bb6ad79423 134 ->dstMemAddr ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 135 ->transferSize ( 360 )
jeroen3 0:46bb6ad79423 136 ->transferType ( MODDMA::m2p )
jeroen3 0:46bb6ad79423 137 ->dstConn ( MODDMA::DAC )
jeroen3 0:46bb6ad79423 138 ->attach_tc ( &TC1_callback )
jeroen3 0:46bb6ad79423 139 ->attach_err ( &ERR1_callback )
jeroen3 0:46bb6ad79423 140 ; // config end
jeroen3 0:46bb6ad79423 141
jeroen3 0:46bb6ad79423 142
jeroen3 0:46bb6ad79423 143 // Calculating the transfer frequency:
jeroen3 0:46bb6ad79423 144 // By default, the Mbed library sets the PCLK_DAC clock value
jeroen3 0:46bb6ad79423 145 // to 24MHz. One complete sinewave cycle in each buffer is 360
jeroen3 0:46bb6ad79423 146 // points long. So, for a 1Hz wave we would need to transfer 360
jeroen3 0:46bb6ad79423 147 // values per second. That would be 24000000/360 which is approx
jeroen3 0:46bb6ad79423 148 // 66,666. But that's no good! The count val is only 16bits in size
jeroen3 0:46bb6ad79423 149 // so bare this in mind. If you need to go slower you will need to
jeroen3 0:46bb6ad79423 150 // alter PCLK_DAC from CCLK/4 to CCLK/8.
jeroen3 0:46bb6ad79423 151 // For our demo we are going to have the sinewave run at 1kHz.
jeroen3 0:46bb6ad79423 152 // That's 24000000/360000 which is approx 66. Experimentation
jeroen3 0:46bb6ad79423 153 // however showed 65 to get closer to 1kHz (on my Mbed and scope
jeroen3 0:46bb6ad79423 154 // at least).
jeroen3 0:46bb6ad79423 155 const double dacclk = 24000000;
jeroen3 0:46bb6ad79423 156 const double dacper = dacclk / 360;
jeroen3 1:b97d61d415ff 157 double ddacdiv;
jeroen3 1:b97d61d415ff 158 switch(mode){
jeroen3 1:b97d61d415ff 159 case MASTER:
jeroen3 1:b97d61d415ff 160 ddacdiv = dacper / (freq_master);
jeroen3 1:b97d61d415ff 161 break;
jeroen3 1:b97d61d415ff 162 case SLAVE:
jeroen3 1:b97d61d415ff 163 ddacdiv = dacper / (freq_slave);
jeroen3 1:b97d61d415ff 164 break;
jeroen3 1:b97d61d415ff 165 }
jeroen3 0:46bb6ad79423 166 unsigned int dacdiv = ddacdiv;
jeroen3 0:46bb6ad79423 167 LPC_DAC->DACCNTVAL = dacdiv; // 6500 for 10Hz
jeroen3 0:46bb6ad79423 168
jeroen3 0:46bb6ad79423 169 // Prepare first configuration.
jeroen3 0:46bb6ad79423 170 if (!dma.Prepare( conf0 )) {
jeroen3 0:46bb6ad79423 171 error("Doh!");
jeroen3 0:46bb6ad79423 172 }
jeroen3 0:46bb6ad79423 173
jeroen3 0:46bb6ad79423 174 if(mode == MASTER){
jeroen3 0:46bb6ad79423 175 wait(0.1);
jeroen3 0:46bb6ad79423 176 }
jeroen3 0:46bb6ad79423 177 wait_for_sync();
jeroen3 0:46bb6ad79423 178
jeroen3 0:46bb6ad79423 179 // Begin (enable DMA and counter). Note, don't enable
jeroen3 0:46bb6ad79423 180 // DBLBUF_ENA as we are using DMA double buffering.
jeroen3 0:46bb6ad79423 181 LPC_DAC->DACCTRL |= (3UL << 2);
jeroen3 0:46bb6ad79423 182
jeroen3 0:46bb6ad79423 183 while (1) {
jeroen3 0:46bb6ad79423 184 // There's not a lot to do as DMA and interrupts are
jeroen3 0:46bb6ad79423 185 // now handling the buffer transfers. So we'll just
jeroen3 0:46bb6ad79423 186 // flash led1 to show the Mbed is alive and kicking.
jeroen3 0:46bb6ad79423 187 if (life_counter++ > 1000000) {
jeroen3 0:46bb6ad79423 188 led1 = !led1; // Show some sort of life.
jeroen3 0:46bb6ad79423 189 life_counter = 0;
jeroen3 0:46bb6ad79423 190 }
jeroen3 0:46bb6ad79423 191 }
jeroen3 0:46bb6ad79423 192 }
jeroen3 0:46bb6ad79423 193
jeroen3 0:46bb6ad79423 194 // Configuration callback on TC
jeroen3 0:46bb6ad79423 195 void TC0_callback(void) {
jeroen3 0:46bb6ad79423 196
jeroen3 0:46bb6ad79423 197
jeroen3 0:46bb6ad79423 198 // Just show sending buffer0 complete.
jeroen3 0:46bb6ad79423 199 led3 = !led3;
jeroen3 0:46bb6ad79423 200
jeroen3 0:46bb6ad79423 201 // Implement wait for trigger if slave mode
jeroen3 0:46bb6ad79423 202 wait_for_sync();
jeroen3 0:46bb6ad79423 203
jeroen3 0:46bb6ad79423 204 // Get configuration pointer.
jeroen3 0:46bb6ad79423 205 MODDMA_Config *config = dma.getConfig();
jeroen3 0:46bb6ad79423 206
jeroen3 0:46bb6ad79423 207 // Finish the DMA cycle by shutting down the channel.
jeroen3 0:46bb6ad79423 208 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
jeroen3 0:46bb6ad79423 209
jeroen3 0:46bb6ad79423 210 // Swap to buffer1
jeroen3 0:46bb6ad79423 211 dma.Prepare( conf1 );
jeroen3 0:46bb6ad79423 212
jeroen3 0:46bb6ad79423 213 // Clear DMA IRQ flags.
jeroen3 0:46bb6ad79423 214 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
jeroen3 0:46bb6ad79423 215 }
jeroen3 0:46bb6ad79423 216
jeroen3 0:46bb6ad79423 217 // Configuration callback on Error
jeroen3 0:46bb6ad79423 218 void ERR0_callback(void) {
jeroen3 0:46bb6ad79423 219 error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
jeroen3 0:46bb6ad79423 220 }
jeroen3 0:46bb6ad79423 221
jeroen3 0:46bb6ad79423 222 // Configuration callback on TC
jeroen3 0:46bb6ad79423 223 void TC1_callback(void) {
jeroen3 0:46bb6ad79423 224
jeroen3 0:46bb6ad79423 225 // Just show sending buffer1 complete.
jeroen3 0:46bb6ad79423 226 led4 = !led4;
jeroen3 0:46bb6ad79423 227
jeroen3 0:46bb6ad79423 228 // Implement wait for trigger if slave mode
jeroen3 0:46bb6ad79423 229 wait_for_sync();
jeroen3 0:46bb6ad79423 230
jeroen3 0:46bb6ad79423 231 // Get configuration pointer.
jeroen3 0:46bb6ad79423 232 MODDMA_Config *config = dma.getConfig();
jeroen3 0:46bb6ad79423 233
jeroen3 0:46bb6ad79423 234 // Finish the DMA cycle by shutting down the channel.
jeroen3 0:46bb6ad79423 235 dma.Disable( (MODDMA::CHANNELS)config->channelNum() );
jeroen3 0:46bb6ad79423 236
jeroen3 0:46bb6ad79423 237 // Swap to buffer0
jeroen3 0:46bb6ad79423 238 dma.Prepare( conf0 );
jeroen3 0:46bb6ad79423 239
jeroen3 0:46bb6ad79423 240 // Clear DMA IRQ flags.
jeroen3 0:46bb6ad79423 241 if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
jeroen3 0:46bb6ad79423 242 }
jeroen3 0:46bb6ad79423 243
jeroen3 0:46bb6ad79423 244 // Configuration callback on Error
jeroen3 0:46bb6ad79423 245 void ERR1_callback(void) {
jeroen3 0:46bb6ad79423 246 error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem");
jeroen3 0:46bb6ad79423 247 }