Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of MODDMA by
example4.h@18:2aa6ffab5522, 2013-08-02 (annotated)
- Committer:
- avbotz
- Date:
- Fri Aug 02 02:21:55 2013 +0000
- Revision:
- 18:2aa6ffab5522
- Parent:
- 16:cb10aec6feb1
Initial commit. Not working. MODDMA makes DMA setup slow, and the mbed SPI peripheral corrupts data sometimes. I will write my own SPI and DMA classes and see how it goes.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AjK | 16:cb10aec6feb1 | 1 | /* |
AjK | 16:cb10aec6feb1 | 2 | * Demonstrates sending a buffer repeatedly to the DAC using DMA. |
AjK | 16:cb10aec6feb1 | 3 | * Connect an oscilloscope to Mbed pin 18. This example doesn't |
AjK | 16:cb10aec6feb1 | 4 | * output anything else (nothing on any serial ports). |
AjK | 16:cb10aec6feb1 | 5 | */ |
AjK | 16:cb10aec6feb1 | 6 | #include "mbed.h" |
AjK | 16:cb10aec6feb1 | 7 | #include "MODDMA.h" |
AjK | 16:cb10aec6feb1 | 8 | |
AjK | 16:cb10aec6feb1 | 9 | // Make the buffer size match the number of degrees |
AjK | 16:cb10aec6feb1 | 10 | // in a circle since we are going to output a sinewave. |
AjK | 16:cb10aec6feb1 | 11 | #define BUFFER_SIZE 360 |
AjK | 16:cb10aec6feb1 | 12 | |
AjK | 16:cb10aec6feb1 | 13 | // Set DAC output power mode. |
AjK | 16:cb10aec6feb1 | 14 | #define DAC_POWER_MODE (1 << 16) |
AjK | 16:cb10aec6feb1 | 15 | |
AjK | 16:cb10aec6feb1 | 16 | DigitalOut led1(LED1); |
AjK | 16:cb10aec6feb1 | 17 | DigitalOut led3(LED3); |
AjK | 16:cb10aec6feb1 | 18 | DigitalOut led4(LED4); |
AjK | 16:cb10aec6feb1 | 19 | |
AjK | 16:cb10aec6feb1 | 20 | int buffer[2][BUFFER_SIZE]; |
AjK | 16:cb10aec6feb1 | 21 | |
AjK | 16:cb10aec6feb1 | 22 | AnalogOut signal(p18); |
AjK | 16:cb10aec6feb1 | 23 | |
AjK | 16:cb10aec6feb1 | 24 | MODDMA dma; |
AjK | 16:cb10aec6feb1 | 25 | MODDMA_Config *conf0, *conf1; |
AjK | 16:cb10aec6feb1 | 26 | |
AjK | 16:cb10aec6feb1 | 27 | void TC0_callback(void); |
AjK | 16:cb10aec6feb1 | 28 | void ERR0_callback(void); |
AjK | 16:cb10aec6feb1 | 29 | |
AjK | 16:cb10aec6feb1 | 30 | void TC1_callback(void); |
AjK | 16:cb10aec6feb1 | 31 | void ERR1_callback(void); |
AjK | 16:cb10aec6feb1 | 32 | |
AjK | 16:cb10aec6feb1 | 33 | int main() { |
AjK | 16:cb10aec6feb1 | 34 | volatile int life_counter = 0; |
AjK | 16:cb10aec6feb1 | 35 | |
AjK | 16:cb10aec6feb1 | 36 | // Create a sinewave buffer for testing. |
AjK | 16:cb10aec6feb1 | 37 | for (int i = 0; i <= 90; i++) buffer[0][i] = (512 * sin(3.14159/180.0 * i)) + 512; |
AjK | 16:cb10aec6feb1 | 38 | for (int i = 91; i <= 180; i++) buffer[0][i] = buffer[0][180 - i]; |
AjK | 16:cb10aec6feb1 | 39 | for (int i = 181; i <= 270; i++) buffer[0][i] = 512 - (buffer[0][i - 180] - 512); |
AjK | 16:cb10aec6feb1 | 40 | for (int i = 271; i < 360; i++) buffer[0][i] = 512 - (buffer[0][360 - i] - 512); |
AjK | 16:cb10aec6feb1 | 41 | |
AjK | 16:cb10aec6feb1 | 42 | // Adjust the sinewave buffer for use with DAC hardware. |
AjK | 16:cb10aec6feb1 | 43 | for (int i = 0; i < 360; i++) { |
AjK | 16:cb10aec6feb1 | 44 | buffer[0][i] = DAC_POWER_MODE | ((buffer[0][i] << 6) & 0xFFC0); |
AjK | 16:cb10aec6feb1 | 45 | buffer[1][i] = buffer[0][i]; // Just create a copy of buffer0 to continue sinewave. |
AjK | 16:cb10aec6feb1 | 46 | } |
AjK | 16:cb10aec6feb1 | 47 | |
AjK | 16:cb10aec6feb1 | 48 | // Prepare the GPDMA system for buffer0. |
AjK | 16:cb10aec6feb1 | 49 | conf0 = new MODDMA_Config; |
AjK | 16:cb10aec6feb1 | 50 | conf0 |
AjK | 16:cb10aec6feb1 | 51 | ->channelNum ( MODDMA::Channel_0 ) |
AjK | 16:cb10aec6feb1 | 52 | ->srcMemAddr ( (uint32_t) &buffer[0] ) |
AjK | 16:cb10aec6feb1 | 53 | ->dstMemAddr ( MODDMA::DAC ) |
AjK | 16:cb10aec6feb1 | 54 | ->transferSize ( 360 ) |
AjK | 16:cb10aec6feb1 | 55 | ->transferType ( MODDMA::m2p ) |
AjK | 16:cb10aec6feb1 | 56 | ->dstConn ( MODDMA::DAC ) |
AjK | 16:cb10aec6feb1 | 57 | ->attach_tc ( &TC0_callback ) |
AjK | 16:cb10aec6feb1 | 58 | ->attach_err ( &ERR0_callback ) |
AjK | 16:cb10aec6feb1 | 59 | ; // config end |
AjK | 16:cb10aec6feb1 | 60 | |
AjK | 16:cb10aec6feb1 | 61 | |
AjK | 16:cb10aec6feb1 | 62 | // Prepare the GPDMA system for buffer1. |
AjK | 16:cb10aec6feb1 | 63 | conf1 = new MODDMA_Config; |
AjK | 16:cb10aec6feb1 | 64 | conf1 |
AjK | 16:cb10aec6feb1 | 65 | ->channelNum ( MODDMA::Channel_1 ) |
AjK | 16:cb10aec6feb1 | 66 | ->srcMemAddr ( (uint32_t) &buffer[1] ) |
AjK | 16:cb10aec6feb1 | 67 | ->dstMemAddr ( MODDMA::DAC ) |
AjK | 16:cb10aec6feb1 | 68 | ->transferSize ( 360 ) |
AjK | 16:cb10aec6feb1 | 69 | ->transferType ( MODDMA::m2p ) |
AjK | 16:cb10aec6feb1 | 70 | ->dstConn ( MODDMA::DAC ) |
AjK | 16:cb10aec6feb1 | 71 | ->attach_tc ( &TC1_callback ) |
AjK | 16:cb10aec6feb1 | 72 | ->attach_err ( &ERR1_callback ) |
AjK | 16:cb10aec6feb1 | 73 | ; // config end |
AjK | 16:cb10aec6feb1 | 74 | |
AjK | 16:cb10aec6feb1 | 75 | |
AjK | 16:cb10aec6feb1 | 76 | // Calculating the transfer frequency: |
AjK | 16:cb10aec6feb1 | 77 | // By default, the Mbed library sets the PCLK_DAC clock value |
AjK | 16:cb10aec6feb1 | 78 | // to 24MHz. One complete sinewave cycle in each buffer is 360 |
AjK | 16:cb10aec6feb1 | 79 | // points long. So, for a 1Hz wave we would need to transfer 360 |
AjK | 16:cb10aec6feb1 | 80 | // values per second. That would be 24000000/360 which is approx |
AjK | 16:cb10aec6feb1 | 81 | // 66,666. But that's no good! The count val is only 16bits in size |
AjK | 16:cb10aec6feb1 | 82 | // so bare this in mind. If you need to go slower you will need to |
AjK | 16:cb10aec6feb1 | 83 | // alter PCLK_DAC from CCLK/4 to CCLK/8. |
AjK | 16:cb10aec6feb1 | 84 | // For our demo we are going to have the sinewave run at 1kHz. |
AjK | 16:cb10aec6feb1 | 85 | // That's 24000000/360000 which is approx 66. Experimentation |
AjK | 16:cb10aec6feb1 | 86 | // however showed 65 to get closer to 1kHz (on my Mbed and scope |
AjK | 16:cb10aec6feb1 | 87 | // at least). |
AjK | 16:cb10aec6feb1 | 88 | LPC_DAC->DACCNTVAL = 65; // 6500 for 10Hz |
AjK | 16:cb10aec6feb1 | 89 | |
AjK | 16:cb10aec6feb1 | 90 | // Prepare first configuration. |
AjK | 16:cb10aec6feb1 | 91 | if (!dma.Prepare( conf0 )) { |
AjK | 16:cb10aec6feb1 | 92 | error("Doh!"); |
AjK | 16:cb10aec6feb1 | 93 | } |
AjK | 16:cb10aec6feb1 | 94 | |
AjK | 16:cb10aec6feb1 | 95 | // Begin (enable DMA and counter). Note, don't enable |
AjK | 16:cb10aec6feb1 | 96 | // DBLBUF_ENA as we are using DMA double buffering. |
AjK | 16:cb10aec6feb1 | 97 | LPC_DAC->DACCTRL |= (3UL << 2); |
AjK | 16:cb10aec6feb1 | 98 | |
AjK | 16:cb10aec6feb1 | 99 | while (1) { |
AjK | 16:cb10aec6feb1 | 100 | // There's not a lot to do as DMA and interrupts are |
AjK | 16:cb10aec6feb1 | 101 | // now handling the buffer transfers. So we'll just |
AjK | 16:cb10aec6feb1 | 102 | // flash led1 to show the Mbed is alive and kicking. |
AjK | 16:cb10aec6feb1 | 103 | if (life_counter++ > 1000000) { |
AjK | 16:cb10aec6feb1 | 104 | led1 = !led1; // Show some sort of life. |
AjK | 16:cb10aec6feb1 | 105 | life_counter = 0; |
AjK | 16:cb10aec6feb1 | 106 | } |
AjK | 16:cb10aec6feb1 | 107 | } |
AjK | 16:cb10aec6feb1 | 108 | } |
AjK | 16:cb10aec6feb1 | 109 | |
AjK | 16:cb10aec6feb1 | 110 | // Configuration callback on TC |
AjK | 16:cb10aec6feb1 | 111 | void TC0_callback(void) { |
AjK | 16:cb10aec6feb1 | 112 | |
AjK | 16:cb10aec6feb1 | 113 | // Just show sending buffer0 complete. |
AjK | 16:cb10aec6feb1 | 114 | led3 = !led3; |
AjK | 16:cb10aec6feb1 | 115 | |
AjK | 16:cb10aec6feb1 | 116 | // Get configuration pointer. |
AjK | 16:cb10aec6feb1 | 117 | MODDMA_Config *config = dma.getConfig(); |
AjK | 16:cb10aec6feb1 | 118 | |
AjK | 16:cb10aec6feb1 | 119 | // Finish the DMA cycle by shutting down the channel. |
AjK | 16:cb10aec6feb1 | 120 | dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); |
AjK | 16:cb10aec6feb1 | 121 | |
AjK | 16:cb10aec6feb1 | 122 | // Swap to buffer1 |
AjK | 16:cb10aec6feb1 | 123 | dma.Prepare( conf1 ); |
AjK | 16:cb10aec6feb1 | 124 | |
AjK | 16:cb10aec6feb1 | 125 | // Clear DMA IRQ flags. |
AjK | 16:cb10aec6feb1 | 126 | if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); |
AjK | 16:cb10aec6feb1 | 127 | } |
AjK | 16:cb10aec6feb1 | 128 | |
AjK | 16:cb10aec6feb1 | 129 | // Configuration callback on Error |
AjK | 16:cb10aec6feb1 | 130 | void ERR0_callback(void) { |
AjK | 16:cb10aec6feb1 | 131 | error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem"); |
AjK | 16:cb10aec6feb1 | 132 | } |
AjK | 16:cb10aec6feb1 | 133 | |
AjK | 16:cb10aec6feb1 | 134 | // Configuration callback on TC |
AjK | 16:cb10aec6feb1 | 135 | void TC1_callback(void) { |
AjK | 16:cb10aec6feb1 | 136 | |
AjK | 16:cb10aec6feb1 | 137 | // Just show sending buffer1 complete. |
AjK | 16:cb10aec6feb1 | 138 | led4 = !led4; |
AjK | 16:cb10aec6feb1 | 139 | |
AjK | 16:cb10aec6feb1 | 140 | // Get configuration pointer. |
AjK | 16:cb10aec6feb1 | 141 | MODDMA_Config *config = dma.getConfig(); |
AjK | 16:cb10aec6feb1 | 142 | |
AjK | 16:cb10aec6feb1 | 143 | // Finish the DMA cycle by shutting down the channel. |
AjK | 16:cb10aec6feb1 | 144 | dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); |
AjK | 16:cb10aec6feb1 | 145 | |
AjK | 16:cb10aec6feb1 | 146 | // Swap to buffer0 |
AjK | 16:cb10aec6feb1 | 147 | dma.Prepare( conf0 ); |
AjK | 16:cb10aec6feb1 | 148 | |
AjK | 16:cb10aec6feb1 | 149 | // Clear DMA IRQ flags. |
AjK | 16:cb10aec6feb1 | 150 | if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); |
AjK | 16:cb10aec6feb1 | 151 | } |
AjK | 16:cb10aec6feb1 | 152 | |
AjK | 16:cb10aec6feb1 | 153 | // Configuration callback on Error |
AjK | 16:cb10aec6feb1 | 154 | void ERR1_callback(void) { |
AjK | 16:cb10aec6feb1 | 155 | error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem"); |
AjK | 16:cb10aec6feb1 | 156 | } |