Allows Asynchronous reading from the analog pins to memory. Supports: K64F

Dependents:   MoppyController

Committer:
Condo2k4
Date:
Wed May 03 12:48:31 2017 +0000
Revision:
1:57441202d8d0
Parent:
0:f0c00f67fba1
Child:
2:754768be9b9a
Removed unused debug import

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Condo2k4 0:f0c00f67fba1 1 #include "asyncADC.h"
Condo2k4 0:f0c00f67fba1 2 #include "pinmap.h"
Condo2k4 0:f0c00f67fba1 3 #include "PeripheralPins.h"
Condo2k4 0:f0c00f67fba1 4 #include "PeripheralNames.h"
Condo2k4 0:f0c00f67fba1 5
Condo2k4 0:f0c00f67fba1 6 #define MAX_MOD (0xFFFF)
Condo2k4 0:f0c00f67fba1 7
Condo2k4 0:f0c00f67fba1 8 static bool _asyncReadActive = false;
Condo2k4 0:f0c00f67fba1 9 static edma_handle_t _handle;
Condo2k4 0:f0c00f67fba1 10 static edma_tcd_t _tcd;
Condo2k4 0:f0c00f67fba1 11 static asyncISR _callback = NULL;
Condo2k4 0:f0c00f67fba1 12 static uint32_t _bufSize;
Condo2k4 0:f0c00f67fba1 13
Condo2k4 0:f0c00f67fba1 14 // MATH SUPPORT FUNCTIONS
Condo2k4 0:f0c00f67fba1 15
Condo2k4 0:f0c00f67fba1 16 float f_abs(float f) {
Condo2k4 0:f0c00f67fba1 17 return f>=0.0f ? f : -f;
Condo2k4 0:f0c00f67fba1 18 }
Condo2k4 0:f0c00f67fba1 19
Condo2k4 0:f0c00f67fba1 20 int i_abs(int i) {
Condo2k4 0:f0c00f67fba1 21 return i>=0 ? i : -i;
Condo2k4 0:f0c00f67fba1 22 }
Condo2k4 0:f0c00f67fba1 23
Condo2k4 0:f0c00f67fba1 24 bool isPowerOfTwo(unsigned int x)
Condo2k4 0:f0c00f67fba1 25 {
Condo2k4 0:f0c00f67fba1 26 return (x != 0) && ((x & (x - 1)) == 0);
Condo2k4 0:f0c00f67fba1 27 }
Condo2k4 0:f0c00f67fba1 28
Condo2k4 0:f0c00f67fba1 29 int log2(unsigned int i) {
Condo2k4 0:f0c00f67fba1 30 int l = 0;
Condo2k4 0:f0c00f67fba1 31 while(i>>=1) l++;
Condo2k4 0:f0c00f67fba1 32 return l;
Condo2k4 0:f0c00f67fba1 33 }
Condo2k4 0:f0c00f67fba1 34
Condo2k4 0:f0c00f67fba1 35 // CLOCK SUPPORT FUNTIONS
Condo2k4 0:f0c00f67fba1 36
Condo2k4 0:f0c00f67fba1 37 void calcClockDiv(const uint32_t targetFrequency, int &divider, bool &useMult, int &modulus) {
Condo2k4 0:f0c00f67fba1 38
Condo2k4 0:f0c00f67fba1 39 uint32_t busClock = CLOCK_GetFreq(kCLOCK_BusClk);
Condo2k4 0:f0c00f67fba1 40
Condo2k4 0:f0c00f67fba1 41 if(targetFrequency > busClock) {
Condo2k4 0:f0c00f67fba1 42 useMult = false;
Condo2k4 0:f0c00f67fba1 43 divider = 0;
Condo2k4 0:f0c00f67fba1 44 modulus = 0;
Condo2k4 0:f0c00f67fba1 45 }
Condo2k4 0:f0c00f67fba1 46
Condo2k4 0:f0c00f67fba1 47 useMult = false;
Condo2k4 0:f0c00f67fba1 48 divider = 0;
Condo2k4 0:f0c00f67fba1 49 modulus = (((busClock<<1)/targetFrequency+1)>>1)-1; // round(clock/freq)-1
Condo2k4 0:f0c00f67fba1 50 int bestErr = i_abs(targetFrequency - busClock/(modulus+1));
Condo2k4 0:f0c00f67fba1 51
Condo2k4 0:f0c00f67fba1 52 for(int i=1; i<=7; i++) {
Condo2k4 0:f0c00f67fba1 53 int mod = (((busClock>>(i-1))/targetFrequency+1)>>1)-1;
Condo2k4 0:f0c00f67fba1 54 if(mod<0) mod=0;
Condo2k4 0:f0c00f67fba1 55 else if(mod > MAX_MOD) mod = MAX_MOD;
Condo2k4 0:f0c00f67fba1 56 int err = i_abs(targetFrequency - busClock/((1<<i) * (mod+1)));
Condo2k4 0:f0c00f67fba1 57
Condo2k4 0:f0c00f67fba1 58 if(err<bestErr || (err==bestErr && mod<modulus)) {
Condo2k4 0:f0c00f67fba1 59 useMult = false;
Condo2k4 0:f0c00f67fba1 60 divider = i;
Condo2k4 0:f0c00f67fba1 61 modulus = mod;
Condo2k4 0:f0c00f67fba1 62 }
Condo2k4 0:f0c00f67fba1 63
Condo2k4 0:f0c00f67fba1 64 mod = (((busClock>>(i-1))/(targetFrequency*5)+1)>>1)-1;
Condo2k4 0:f0c00f67fba1 65 if(mod<0) mod=0;
Condo2k4 0:f0c00f67fba1 66 else if(mod > MAX_MOD) mod = MAX_MOD;
Condo2k4 0:f0c00f67fba1 67 err = i_abs(targetFrequency - busClock/((1<<i) * (mod+1) * 5));
Condo2k4 0:f0c00f67fba1 68
Condo2k4 0:f0c00f67fba1 69 if(err<bestErr || (err==bestErr && mod<modulus)) {
Condo2k4 0:f0c00f67fba1 70 useMult = true;
Condo2k4 0:f0c00f67fba1 71 divider = i;
Condo2k4 0:f0c00f67fba1 72 modulus = mod;
Condo2k4 0:f0c00f67fba1 73 }
Condo2k4 0:f0c00f67fba1 74
Condo2k4 0:f0c00f67fba1 75 }
Condo2k4 0:f0c00f67fba1 76 for(int i=8; i<=11; i++) {
Condo2k4 0:f0c00f67fba1 77 int mod = (((busClock>>(i-1))/(targetFrequency*5)+1)>>1)-1;
Condo2k4 0:f0c00f67fba1 78 if(mod<0) mod=0;
Condo2k4 0:f0c00f67fba1 79 else if(mod > MAX_MOD) mod = MAX_MOD;
Condo2k4 0:f0c00f67fba1 80 int err = i_abs(targetFrequency - busClock/((1<<i) * (mod+1) * 5));
Condo2k4 0:f0c00f67fba1 81
Condo2k4 0:f0c00f67fba1 82 if(err<bestErr || (err==bestErr && mod<modulus)) {
Condo2k4 0:f0c00f67fba1 83 useMult = true;
Condo2k4 0:f0c00f67fba1 84 divider = i;
Condo2k4 0:f0c00f67fba1 85 modulus = mod;
Condo2k4 0:f0c00f67fba1 86 }
Condo2k4 0:f0c00f67fba1 87 }
Condo2k4 0:f0c00f67fba1 88
Condo2k4 0:f0c00f67fba1 89 if(modulus > MAX_MOD)
Condo2k4 0:f0c00f67fba1 90 modulus = MAX_MOD;
Condo2k4 0:f0c00f67fba1 91 }
Condo2k4 0:f0c00f67fba1 92
Condo2k4 0:f0c00f67fba1 93 void calcClockDiv(const float targetFrequency, int &divider, bool &useMult, int &modulus) {
Condo2k4 0:f0c00f67fba1 94
Condo2k4 0:f0c00f67fba1 95 uint32_t busClock = CLOCK_GetFreq(kCLOCK_BusClk);
Condo2k4 0:f0c00f67fba1 96
Condo2k4 0:f0c00f67fba1 97 if(targetFrequency > busClock) {
Condo2k4 0:f0c00f67fba1 98 useMult = false;
Condo2k4 0:f0c00f67fba1 99 divider = 0;
Condo2k4 0:f0c00f67fba1 100 modulus = 0;
Condo2k4 0:f0c00f67fba1 101 return;
Condo2k4 0:f0c00f67fba1 102 }
Condo2k4 0:f0c00f67fba1 103
Condo2k4 0:f0c00f67fba1 104 useMult = false;
Condo2k4 0:f0c00f67fba1 105 divider = 0;
Condo2k4 0:f0c00f67fba1 106 modulus = (int)((busClock/targetFrequency)+0.5f); // round(clock/freq)
Condo2k4 0:f0c00f67fba1 107 float bestErr = f_abs(targetFrequency - busClock/(modulus+1));
Condo2k4 0:f0c00f67fba1 108
Condo2k4 0:f0c00f67fba1 109 for(int i=1; i<=7; i++) {
Condo2k4 0:f0c00f67fba1 110 int mod = (int)(((busClock>>i)/targetFrequency)+0.5f);
Condo2k4 0:f0c00f67fba1 111 if(mod<0) mod=0;
Condo2k4 0:f0c00f67fba1 112 else if(mod > MAX_MOD) mod = MAX_MOD;
Condo2k4 0:f0c00f67fba1 113 float err = f_abs(targetFrequency - busClock/(float)((1<<i) * (mod+1)));
Condo2k4 0:f0c00f67fba1 114
Condo2k4 0:f0c00f67fba1 115 if(err<bestErr || (err==bestErr && mod<modulus)) {
Condo2k4 0:f0c00f67fba1 116 useMult = false;
Condo2k4 0:f0c00f67fba1 117 divider = i;
Condo2k4 0:f0c00f67fba1 118 modulus = mod;
Condo2k4 0:f0c00f67fba1 119 }
Condo2k4 0:f0c00f67fba1 120
Condo2k4 0:f0c00f67fba1 121 mod = (int)(((busClock>>i)/(targetFrequency*5.0f))+0.5f);
Condo2k4 0:f0c00f67fba1 122 if(mod<0) mod=0;
Condo2k4 0:f0c00f67fba1 123 else if(mod > MAX_MOD) mod = MAX_MOD;
Condo2k4 0:f0c00f67fba1 124 err = f_abs(targetFrequency - busClock/(float)((1<<i) * (mod+1) * 5));
Condo2k4 0:f0c00f67fba1 125
Condo2k4 0:f0c00f67fba1 126 if(err<bestErr || (err==bestErr && mod<modulus)) {
Condo2k4 0:f0c00f67fba1 127 useMult = true;
Condo2k4 0:f0c00f67fba1 128 divider = i;
Condo2k4 0:f0c00f67fba1 129 modulus = mod;
Condo2k4 0:f0c00f67fba1 130 }
Condo2k4 0:f0c00f67fba1 131
Condo2k4 0:f0c00f67fba1 132 }
Condo2k4 0:f0c00f67fba1 133 for(int i=8; i<=11; i++) {
Condo2k4 0:f0c00f67fba1 134 int mod = (int)(((busClock>>i)/(targetFrequency*5.0f))+0.5f);
Condo2k4 0:f0c00f67fba1 135 if(mod<0) mod=0;
Condo2k4 0:f0c00f67fba1 136 else if(mod > MAX_MOD) mod = MAX_MOD;
Condo2k4 0:f0c00f67fba1 137 float err = f_abs(targetFrequency - busClock/(float)((1<<i) * (mod+1) * 5));
Condo2k4 0:f0c00f67fba1 138
Condo2k4 0:f0c00f67fba1 139 if(err<bestErr || (err==bestErr && mod<modulus)) {
Condo2k4 0:f0c00f67fba1 140 useMult = true;
Condo2k4 0:f0c00f67fba1 141 divider = i;
Condo2k4 0:f0c00f67fba1 142 modulus = mod;
Condo2k4 0:f0c00f67fba1 143 }
Condo2k4 0:f0c00f67fba1 144 }
Condo2k4 0:f0c00f67fba1 145 }
Condo2k4 0:f0c00f67fba1 146
Condo2k4 0:f0c00f67fba1 147 // INTERRUPT SERVICE ROUTINES
Condo2k4 0:f0c00f67fba1 148
Condo2k4 0:f0c00f67fba1 149 void singleISR(edma_handle_t *_handle, void *userData, bool transferDone, uint32_t tcds) {
Condo2k4 0:f0c00f67fba1 150 PDB_Enable(PDB0, false);
Condo2k4 0:f0c00f67fba1 151 _asyncReadActive = false;
Condo2k4 0:f0c00f67fba1 152 if(_callback!=NULL) _callback(0, _bufSize);
Condo2k4 0:f0c00f67fba1 153 }
Condo2k4 0:f0c00f67fba1 154
Condo2k4 0:f0c00f67fba1 155 void rollingISR(edma_handle_t *_handle, void *userData, bool transferDone, uint32_t tcds) {
Condo2k4 0:f0c00f67fba1 156 if(_callback!=NULL) {
Condo2k4 0:f0c00f67fba1 157 if(_handle->base->TCD[_handle->channel].CSR & DMA_CSR_DONE_MASK)
Condo2k4 0:f0c00f67fba1 158 _callback(_bufSize>>1, _bufSize-1);
Condo2k4 0:f0c00f67fba1 159 else
Condo2k4 0:f0c00f67fba1 160 _callback(0, (_bufSize>>1)-1);
Condo2k4 0:f0c00f67fba1 161 }
Condo2k4 0:f0c00f67fba1 162 }
Condo2k4 0:f0c00f67fba1 163
Condo2k4 0:f0c00f67fba1 164 // INIT METHODS
Condo2k4 0:f0c00f67fba1 165
Condo2k4 0:f0c00f67fba1 166 void prepareADC(uint8_t adcIndex, uint8_t channelGroup, uint8_t channel) {
Condo2k4 0:f0c00f67fba1 167
Condo2k4 0:f0c00f67fba1 168 ADC_Type* adc;
Condo2k4 0:f0c00f67fba1 169
Condo2k4 0:f0c00f67fba1 170 if(adcIndex) {
Condo2k4 0:f0c00f67fba1 171 SIM->SCGC3 |= SIM_SCGC3_ADC1_MASK;
Condo2k4 0:f0c00f67fba1 172 adc = ADC1;
Condo2k4 0:f0c00f67fba1 173 } else {
Condo2k4 0:f0c00f67fba1 174 SIM->SCGC6 |= SIM_SCGC6_ADC0_MASK;
Condo2k4 0:f0c00f67fba1 175 adc = ADC0;
Condo2k4 0:f0c00f67fba1 176 }
Condo2k4 0:f0c00f67fba1 177
Condo2k4 0:f0c00f67fba1 178 adc16_config_t adc16ConfigStruct;
Condo2k4 0:f0c00f67fba1 179
Condo2k4 0:f0c00f67fba1 180 ADC16_GetDefaultConfig(&adc16ConfigStruct);
Condo2k4 0:f0c00f67fba1 181 ADC16_Init(adc, &adc16ConfigStruct);
Condo2k4 0:f0c00f67fba1 182 ADC16_EnableHardwareTrigger(adc, true);
Condo2k4 0:f0c00f67fba1 183 ADC16_DoAutoCalibration(adc);
Condo2k4 0:f0c00f67fba1 184 ADC16_EnableHardwareTrigger(adc, true);
Condo2k4 0:f0c00f67fba1 185 ADC16_EnableDMA(adc, true);
Condo2k4 0:f0c00f67fba1 186
Condo2k4 0:f0c00f67fba1 187 adc16_channel_config_t channelConfig;
Condo2k4 0:f0c00f67fba1 188
Condo2k4 0:f0c00f67fba1 189 channelConfig.channelNumber = channel;
Condo2k4 0:f0c00f67fba1 190 channelConfig.enableInterruptOnConversionCompleted = false;
Condo2k4 0:f0c00f67fba1 191 channelConfig.enableDifferentialConversion = false;
Condo2k4 0:f0c00f67fba1 192
Condo2k4 0:f0c00f67fba1 193 ADC16_SetChannelConfig(adc, channelGroup, &channelConfig);
Condo2k4 0:f0c00f67fba1 194 }
Condo2k4 0:f0c00f67fba1 195
Condo2k4 0:f0c00f67fba1 196 status_t prepareDMA(uint16_t* destination, uint32_t destSize, int16_t dmaChannel, uint8_t adcIndex, uint8_t adcGroup, bool rollingMode) {
Condo2k4 0:f0c00f67fba1 197 if(dmaChannel<0) {
Condo2k4 0:f0c00f67fba1 198 //Find free DMA channel
Condo2k4 0:f0c00f67fba1 199 for(int i=0; i<16; i++) {
Condo2k4 0:f0c00f67fba1 200 if((DMA0->ERQ & (1U<<i)) == 0) {
Condo2k4 0:f0c00f67fba1 201 dmaChannel=i;
Condo2k4 0:f0c00f67fba1 202 break;
Condo2k4 0:f0c00f67fba1 203 }
Condo2k4 0:f0c00f67fba1 204 }
Condo2k4 0:f0c00f67fba1 205 if(dmaChannel<0)
Condo2k4 0:f0c00f67fba1 206 return kStatus_EDMA_Busy;
Condo2k4 0:f0c00f67fba1 207 } else {
Condo2k4 0:f0c00f67fba1 208 //check if requested DMA channel is free
Condo2k4 0:f0c00f67fba1 209 if((dmaChannel>15) || DMA0->ERQ & (1U<<dmaChannel))
Condo2k4 0:f0c00f67fba1 210 return kStatus_EDMA_Busy;
Condo2k4 0:f0c00f67fba1 211 }
Condo2k4 0:f0c00f67fba1 212
Condo2k4 0:f0c00f67fba1 213 /* Configure DMAMUX */
Condo2k4 0:f0c00f67fba1 214 DMAMUX_Init(DMAMUX0);
Condo2k4 0:f0c00f67fba1 215 DMAMUX_SetSource(DMAMUX0, dmaChannel, 40+adcIndex); //Trigger 40 = ADC0, 41 = ADC1
Condo2k4 0:f0c00f67fba1 216 DMAMUX_EnableChannel(DMAMUX0, dmaChannel);
Condo2k4 0:f0c00f67fba1 217
Condo2k4 0:f0c00f67fba1 218 edma_config_t edma_config;
Condo2k4 0:f0c00f67fba1 219
Condo2k4 0:f0c00f67fba1 220 /* Init the eDMA driver */
Condo2k4 0:f0c00f67fba1 221 EDMA_GetDefaultConfig(&edma_config);
Condo2k4 0:f0c00f67fba1 222
Condo2k4 0:f0c00f67fba1 223 EDMA_Init(DMA0, &edma_config);
Condo2k4 0:f0c00f67fba1 224
Condo2k4 0:f0c00f67fba1 225 EDMA_CreateHandle(&_handle, DMA0, dmaChannel);
Condo2k4 0:f0c00f67fba1 226 EDMA_InstallTCDMemory(&_handle, NULL, 0); //make sure tcd memory pool is clear
Condo2k4 0:f0c00f67fba1 227 EDMA_SetCallback(&_handle, rollingMode ? rollingISR : singleISR, NULL);
Condo2k4 0:f0c00f67fba1 228
Condo2k4 0:f0c00f67fba1 229
Condo2k4 0:f0c00f67fba1 230 if(rollingMode) {
Condo2k4 0:f0c00f67fba1 231 EDMA_SetModulo(DMA0, dmaChannel, (edma_modulo_t)(log2(destSize)+1), kEDMA_ModuloDisable);
Condo2k4 0:f0c00f67fba1 232 _handle.base->TCD[dmaChannel].DLAST_SGA = -2*(int32_t)destSize;
Condo2k4 0:f0c00f67fba1 233 }
Condo2k4 0:f0c00f67fba1 234
Condo2k4 0:f0c00f67fba1 235 edma_transfer_config_t transfer_config;
Condo2k4 0:f0c00f67fba1 236 EDMA_PrepareTransfer(&transfer_config, (void*)&((adcIndex?ADC1:ADC0)->R[adcGroup]), 2, destination, 2, 2, 2*destSize, kEDMA_PeripheralToMemory);
Condo2k4 0:f0c00f67fba1 237 status_t ret = EDMA_SubmitTransfer(&_handle, &transfer_config);
Condo2k4 0:f0c00f67fba1 238
Condo2k4 0:f0c00f67fba1 239 if(rollingMode)
Condo2k4 0:f0c00f67fba1 240 EDMA_EnableAutoStopRequest(DMA0, dmaChannel, false); //must go after submit
Condo2k4 0:f0c00f67fba1 241
Condo2k4 0:f0c00f67fba1 242 if(ret == kStatus_Success) {
Condo2k4 0:f0c00f67fba1 243 EDMA_EnableChannelInterrupts(DMA0, dmaChannel, rollingMode ? (kEDMA_MajorInterruptEnable|kEDMA_HalfInterruptEnable) : kEDMA_MajorInterruptEnable);
Condo2k4 0:f0c00f67fba1 244 EDMA_StartTransfer(&_handle);
Condo2k4 0:f0c00f67fba1 245 }
Condo2k4 0:f0c00f67fba1 246
Condo2k4 0:f0c00f67fba1 247 return ret;
Condo2k4 0:f0c00f67fba1 248 }
Condo2k4 0:f0c00f67fba1 249
Condo2k4 0:f0c00f67fba1 250 void preparePDB(int divider, bool useMult, int modulus, uint8_t adcIndex, uint8_t adcGroup) {
Condo2k4 0:f0c00f67fba1 251 SIM->SCGC6 |= SIM_SCGC6_PDB_MASK;
Condo2k4 0:f0c00f67fba1 252
Condo2k4 0:f0c00f67fba1 253 pdb_config_t config;
Condo2k4 0:f0c00f67fba1 254 PDB_GetDefaultConfig(&config);
Condo2k4 0:f0c00f67fba1 255 if(useMult) {
Condo2k4 0:f0c00f67fba1 256 switch(divider) {
Condo2k4 0:f0c00f67fba1 257 case 1:
Condo2k4 0:f0c00f67fba1 258 config.dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor10;
Condo2k4 0:f0c00f67fba1 259 divider = 0;
Condo2k4 0:f0c00f67fba1 260 break;
Condo2k4 0:f0c00f67fba1 261 case 2:
Condo2k4 0:f0c00f67fba1 262 config.dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor20;
Condo2k4 0:f0c00f67fba1 263 divider = 0;
Condo2k4 0:f0c00f67fba1 264 break;
Condo2k4 0:f0c00f67fba1 265 default:
Condo2k4 0:f0c00f67fba1 266 config.dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor40;
Condo2k4 0:f0c00f67fba1 267 divider-=3;
Condo2k4 0:f0c00f67fba1 268 break;
Condo2k4 0:f0c00f67fba1 269 }
Condo2k4 0:f0c00f67fba1 270 } else {
Condo2k4 0:f0c00f67fba1 271 config.dividerMultiplicationFactor = kPDB_DividerMultiplicationFactor1;
Condo2k4 0:f0c00f67fba1 272 }
Condo2k4 0:f0c00f67fba1 273
Condo2k4 0:f0c00f67fba1 274 switch(divider) {
Condo2k4 0:f0c00f67fba1 275 case 0:
Condo2k4 0:f0c00f67fba1 276 config.prescalerDivider = kPDB_PrescalerDivider1;
Condo2k4 0:f0c00f67fba1 277 break;
Condo2k4 0:f0c00f67fba1 278 case 1:
Condo2k4 0:f0c00f67fba1 279 config.prescalerDivider = kPDB_PrescalerDivider2;
Condo2k4 0:f0c00f67fba1 280 break;
Condo2k4 0:f0c00f67fba1 281 case 2:
Condo2k4 0:f0c00f67fba1 282 config.prescalerDivider = kPDB_PrescalerDivider4;
Condo2k4 0:f0c00f67fba1 283 break;
Condo2k4 0:f0c00f67fba1 284 case 3:
Condo2k4 0:f0c00f67fba1 285 config.prescalerDivider = kPDB_PrescalerDivider8;
Condo2k4 0:f0c00f67fba1 286 break;
Condo2k4 0:f0c00f67fba1 287 case 4:
Condo2k4 0:f0c00f67fba1 288 config.prescalerDivider = kPDB_PrescalerDivider16;
Condo2k4 0:f0c00f67fba1 289 break;
Condo2k4 0:f0c00f67fba1 290 case 5:
Condo2k4 0:f0c00f67fba1 291 config.prescalerDivider = kPDB_PrescalerDivider32;
Condo2k4 0:f0c00f67fba1 292 break;
Condo2k4 0:f0c00f67fba1 293 case 6:
Condo2k4 0:f0c00f67fba1 294 config.prescalerDivider = kPDB_PrescalerDivider64;
Condo2k4 0:f0c00f67fba1 295 break;
Condo2k4 0:f0c00f67fba1 296 default:
Condo2k4 0:f0c00f67fba1 297 config.prescalerDivider = kPDB_PrescalerDivider128;
Condo2k4 0:f0c00f67fba1 298 break;
Condo2k4 0:f0c00f67fba1 299 }
Condo2k4 0:f0c00f67fba1 300
Condo2k4 0:f0c00f67fba1 301 config.loadValueMode = kPDB_LoadValueImmediately;
Condo2k4 0:f0c00f67fba1 302 config.triggerInputSource = kPDB_TriggerSoftware;
Condo2k4 0:f0c00f67fba1 303 config.enableContinuousMode = true;
Condo2k4 0:f0c00f67fba1 304 PDB_Init(PDB0, &config);
Condo2k4 0:f0c00f67fba1 305
Condo2k4 0:f0c00f67fba1 306 PDB_EnableDMA(PDB0, false); //set if PDB signals DMA directly instead of generating hardware interrupt
Condo2k4 0:f0c00f67fba1 307 PDB_DisableInterrupts(PDB0, kPDB_SequenceErrorInterruptEnable); //signal errors with interrupt?
Condo2k4 0:f0c00f67fba1 308 PDB_EnableInterrupts(PDB0, kPDB_DelayInterruptEnable); //send interrupt after delay?
Condo2k4 0:f0c00f67fba1 309
Condo2k4 0:f0c00f67fba1 310 pdb_adc_pretrigger_config_t adcConfig;
Condo2k4 0:f0c00f67fba1 311 adcConfig.enablePreTriggerMask = 1; //enable pre-trigger 0
Condo2k4 0:f0c00f67fba1 312 adcConfig.enableOutputMask = 1; //enable output for pre-trigger 0
Condo2k4 0:f0c00f67fba1 313 adcConfig.enableBackToBackOperationMask = 0; //disable back-to-back for all pre-triggers
Condo2k4 0:f0c00f67fba1 314 PDB_SetADCPreTriggerConfig(PDB0, adcIndex, &adcConfig);
Condo2k4 0:f0c00f67fba1 315
Condo2k4 0:f0c00f67fba1 316 PDB_SetADCPreTriggerDelayValue(PDB0, 0, 0, 0); //set delay on ADC0->R[0]
Condo2k4 0:f0c00f67fba1 317 PDB_SetADCPreTriggerDelayValue(PDB0, 0, 1, 0); //set delay on ADC0->R[1]
Condo2k4 0:f0c00f67fba1 318 PDB_SetADCPreTriggerDelayValue(PDB0, 1, 0, 0); //set delay on ADC1->R[0]
Condo2k4 0:f0c00f67fba1 319 PDB_SetADCPreTriggerDelayValue(PDB0, 1, 1, 0); //set delay on ADC1->R[1]
Condo2k4 0:f0c00f67fba1 320
Condo2k4 0:f0c00f67fba1 321 PDB_SetModulusValue(PDB0, modulus); //actual frequency = clock frequency / ((modulus+1) * prescale divider * divider multiplier)
Condo2k4 0:f0c00f67fba1 322
Condo2k4 0:f0c00f67fba1 323 PDB_Enable(PDB0, true); //do at end before load
Condo2k4 0:f0c00f67fba1 324 PDB_DoLoadValues(PDB0);
Condo2k4 0:f0c00f67fba1 325 }
Condo2k4 0:f0c00f67fba1 326
Condo2k4 0:f0c00f67fba1 327 // API
Condo2k4 0:f0c00f67fba1 328
Condo2k4 0:f0c00f67fba1 329 uint32_t approximateFrequency(uint32_t targetFrequency) {
Condo2k4 0:f0c00f67fba1 330 int divider, modulus; bool useMult;
Condo2k4 0:f0c00f67fba1 331 calcClockDiv(targetFrequency, divider, useMult, modulus);
Condo2k4 0:f0c00f67fba1 332 return (CLOCK_GetFreq(kCLOCK_BusClk)/((1<<divider) * (modulus+1) * (useMult ? 10 : 2))+1)>>1;
Condo2k4 0:f0c00f67fba1 333 }
Condo2k4 0:f0c00f67fba1 334
Condo2k4 0:f0c00f67fba1 335 float approximateFrequency(float targetFrequency) {
Condo2k4 0:f0c00f67fba1 336 int divider, modulus; bool useMult;
Condo2k4 0:f0c00f67fba1 337 calcClockDiv(targetFrequency, divider, useMult, modulus);
Condo2k4 0:f0c00f67fba1 338 return CLOCK_GetFreq(kCLOCK_BusClk)/(float)((1<<divider) * (modulus+1) * (useMult ? 5 : 1));
Condo2k4 0:f0c00f67fba1 339 }
Condo2k4 0:f0c00f67fba1 340
Condo2k4 0:f0c00f67fba1 341 async_error_t asyncAnalogToBuffer(PinName source, uint16_t* destination, uint32_t destSize, uint32_t sampleFrequency, asyncISR callback, int16_t dmaChannel) {
Condo2k4 0:f0c00f67fba1 342 if(_asyncReadActive)
Condo2k4 0:f0c00f67fba1 343 return E_ASYNC_ADC_ACTIVE;
Condo2k4 0:f0c00f67fba1 344 _asyncReadActive = true;
Condo2k4 0:f0c00f67fba1 345
Condo2k4 0:f0c00f67fba1 346 if(destSize<=0) {
Condo2k4 0:f0c00f67fba1 347 return E_INVALID_BUFFER_SIZE; //Destination buffer size must be greater that 0
Condo2k4 0:f0c00f67fba1 348 }
Condo2k4 0:f0c00f67fba1 349
Condo2k4 0:f0c00f67fba1 350 uint32_t adc = pinmap_peripheral(source, PinMap_ADC);
Condo2k4 0:f0c00f67fba1 351
Condo2k4 0:f0c00f67fba1 352 if(adc == (ADCName)NC) {
Condo2k4 0:f0c00f67fba1 353 error("Pin doese not support Analog to Digital Conversion");
Condo2k4 0:f0c00f67fba1 354 }
Condo2k4 0:f0c00f67fba1 355
Condo2k4 0:f0c00f67fba1 356 int adcIndex = adc >> ADC_INSTANCE_SHIFT, adcGroup = 0, adcChannel = adc & 0xF;
Condo2k4 0:f0c00f67fba1 357 prepareADC(adcIndex, adcGroup, adcChannel);
Condo2k4 0:f0c00f67fba1 358
Condo2k4 0:f0c00f67fba1 359 switch(prepareDMA(destination, destSize, dmaChannel, adcIndex, adcGroup, false)) {
Condo2k4 0:f0c00f67fba1 360 case kStatus_EDMA_QueueFull:
Condo2k4 0:f0c00f67fba1 361 case kStatus_EDMA_Busy:
Condo2k4 0:f0c00f67fba1 362 return E_DMA_IN_USE;
Condo2k4 0:f0c00f67fba1 363 default:
Condo2k4 0:f0c00f67fba1 364 break;
Condo2k4 0:f0c00f67fba1 365 }
Condo2k4 0:f0c00f67fba1 366
Condo2k4 0:f0c00f67fba1 367 int divider, modulus; bool useMult;
Condo2k4 0:f0c00f67fba1 368 calcClockDiv(sampleFrequency, divider, useMult, modulus);
Condo2k4 0:f0c00f67fba1 369 preparePDB(divider, useMult, modulus, adcIndex, adcGroup);
Condo2k4 0:f0c00f67fba1 370
Condo2k4 0:f0c00f67fba1 371 _bufSize = destSize;
Condo2k4 0:f0c00f67fba1 372 _callback = callback;
Condo2k4 0:f0c00f67fba1 373
Condo2k4 0:f0c00f67fba1 374 PDB_DoSoftwareTrigger(PDB0);
Condo2k4 0:f0c00f67fba1 375
Condo2k4 0:f0c00f67fba1 376 return SUCCESS;
Condo2k4 0:f0c00f67fba1 377 }
Condo2k4 0:f0c00f67fba1 378
Condo2k4 0:f0c00f67fba1 379 async_error_t asyncAnalogToCircularBuffer(PinName source, uint16_t* destination, uint32_t destSize, uint32_t sampleFrequency, asyncISR callback, int16_t dmaChannel) {
Condo2k4 0:f0c00f67fba1 380 if(_asyncReadActive)
Condo2k4 0:f0c00f67fba1 381 return E_ASYNC_ADC_ACTIVE;
Condo2k4 0:f0c00f67fba1 382 _asyncReadActive = true;
Condo2k4 0:f0c00f67fba1 383
Condo2k4 0:f0c00f67fba1 384 if(destSize<=0 && !isPowerOfTwo(destSize)) {
Condo2k4 0:f0c00f67fba1 385 return E_INVALID_BUFFER_SIZE; //Destination buffer size must be greater that 0 and a power of 2
Condo2k4 0:f0c00f67fba1 386 }
Condo2k4 0:f0c00f67fba1 387
Condo2k4 0:f0c00f67fba1 388 uint32_t adc = pinmap_peripheral(source, PinMap_ADC);
Condo2k4 0:f0c00f67fba1 389
Condo2k4 0:f0c00f67fba1 390 if(adc == (ADCName)NC) {
Condo2k4 0:f0c00f67fba1 391 error("Pin doese not support Analog to Digital Conversion");
Condo2k4 0:f0c00f67fba1 392 }
Condo2k4 0:f0c00f67fba1 393
Condo2k4 0:f0c00f67fba1 394 int adcIndex = adc >> ADC_INSTANCE_SHIFT, adcGroup = 0, adcChannel = adc & 0xF;
Condo2k4 0:f0c00f67fba1 395 prepareADC(adcIndex, adcGroup, adcChannel);
Condo2k4 0:f0c00f67fba1 396
Condo2k4 0:f0c00f67fba1 397 switch(prepareDMA(destination, destSize, dmaChannel, adcIndex, adcGroup, true)) {
Condo2k4 0:f0c00f67fba1 398 case kStatus_EDMA_QueueFull:
Condo2k4 0:f0c00f67fba1 399 case kStatus_EDMA_Busy:
Condo2k4 0:f0c00f67fba1 400 return E_DMA_IN_USE;
Condo2k4 0:f0c00f67fba1 401 default:
Condo2k4 0:f0c00f67fba1 402 break;
Condo2k4 0:f0c00f67fba1 403 }
Condo2k4 0:f0c00f67fba1 404
Condo2k4 0:f0c00f67fba1 405 int divider, modulus; bool useMult;
Condo2k4 0:f0c00f67fba1 406 calcClockDiv(sampleFrequency, divider, useMult, modulus);
Condo2k4 0:f0c00f67fba1 407 preparePDB(divider, useMult, modulus, adcIndex, adcGroup);
Condo2k4 0:f0c00f67fba1 408
Condo2k4 0:f0c00f67fba1 409 _bufSize = destSize;
Condo2k4 0:f0c00f67fba1 410 _callback = callback;
Condo2k4 0:f0c00f67fba1 411
Condo2k4 0:f0c00f67fba1 412 PDB_DoSoftwareTrigger(PDB0);
Condo2k4 0:f0c00f67fba1 413
Condo2k4 0:f0c00f67fba1 414 return SUCCESS;
Condo2k4 0:f0c00f67fba1 415 }
Condo2k4 0:f0c00f67fba1 416
Condo2k4 0:f0c00f67fba1 417 async_error_t asyncAnalogToBuffer_f(PinName source, uint16_t* destination, uint32_t destSize, float sampleFrequency, asyncISR callback, int16_t dmaChannel) {
Condo2k4 0:f0c00f67fba1 418 if(_asyncReadActive)
Condo2k4 0:f0c00f67fba1 419 return E_ASYNC_ADC_ACTIVE;
Condo2k4 0:f0c00f67fba1 420 _asyncReadActive = true;
Condo2k4 0:f0c00f67fba1 421
Condo2k4 0:f0c00f67fba1 422 if(destSize<=0) {
Condo2k4 0:f0c00f67fba1 423 return E_INVALID_BUFFER_SIZE; //Destination buffer size must be greater that 0
Condo2k4 0:f0c00f67fba1 424 }
Condo2k4 0:f0c00f67fba1 425
Condo2k4 0:f0c00f67fba1 426 uint32_t adc = pinmap_peripheral(source, PinMap_ADC);
Condo2k4 0:f0c00f67fba1 427
Condo2k4 0:f0c00f67fba1 428 if(adc == (ADCName)NC) {
Condo2k4 0:f0c00f67fba1 429 error("Pin doese not support Analog to Digital Conversion");
Condo2k4 0:f0c00f67fba1 430 }
Condo2k4 0:f0c00f67fba1 431
Condo2k4 0:f0c00f67fba1 432 int adcIndex = adc >> ADC_INSTANCE_SHIFT, adcGroup = 0, adcChannel = adc & 0xF;
Condo2k4 0:f0c00f67fba1 433 prepareADC(adcIndex, adcGroup, adcChannel);
Condo2k4 0:f0c00f67fba1 434
Condo2k4 0:f0c00f67fba1 435 switch(prepareDMA(destination, destSize, dmaChannel, adcIndex, adcGroup, false)) {
Condo2k4 0:f0c00f67fba1 436 case kStatus_EDMA_QueueFull:
Condo2k4 0:f0c00f67fba1 437 case kStatus_EDMA_Busy:
Condo2k4 0:f0c00f67fba1 438 return E_DMA_IN_USE;
Condo2k4 0:f0c00f67fba1 439 default:
Condo2k4 0:f0c00f67fba1 440 break;
Condo2k4 0:f0c00f67fba1 441 }
Condo2k4 0:f0c00f67fba1 442
Condo2k4 0:f0c00f67fba1 443 int divider, modulus; bool useMult;
Condo2k4 0:f0c00f67fba1 444 calcClockDiv(sampleFrequency, divider, useMult, modulus);
Condo2k4 0:f0c00f67fba1 445 preparePDB(divider, useMult, modulus, adcIndex, adcGroup);
Condo2k4 0:f0c00f67fba1 446
Condo2k4 0:f0c00f67fba1 447 _bufSize = destSize;
Condo2k4 0:f0c00f67fba1 448 _callback = callback;
Condo2k4 0:f0c00f67fba1 449
Condo2k4 0:f0c00f67fba1 450 PDB_DoSoftwareTrigger(PDB0);
Condo2k4 0:f0c00f67fba1 451
Condo2k4 0:f0c00f67fba1 452 return SUCCESS;
Condo2k4 0:f0c00f67fba1 453 }
Condo2k4 0:f0c00f67fba1 454
Condo2k4 0:f0c00f67fba1 455 async_error_t asyncAnalogToCircularBuffer_f(PinName source, uint16_t* destination, uint32_t destSize, float sampleFrequency, asyncISR callback, int16_t dmaChannel) {
Condo2k4 0:f0c00f67fba1 456 if(_asyncReadActive)
Condo2k4 0:f0c00f67fba1 457 return E_ASYNC_ADC_ACTIVE;
Condo2k4 0:f0c00f67fba1 458 _asyncReadActive = true;
Condo2k4 0:f0c00f67fba1 459
Condo2k4 0:f0c00f67fba1 460 if(destSize<=0 && !isPowerOfTwo(destSize)) {
Condo2k4 0:f0c00f67fba1 461 return E_INVALID_BUFFER_SIZE; //Destination buffer size must be greater that 0 and a power of 2
Condo2k4 0:f0c00f67fba1 462 }
Condo2k4 0:f0c00f67fba1 463
Condo2k4 0:f0c00f67fba1 464 uint32_t adc = pinmap_peripheral(source, PinMap_ADC);
Condo2k4 0:f0c00f67fba1 465
Condo2k4 0:f0c00f67fba1 466 if(adc == (ADCName)NC) {
Condo2k4 0:f0c00f67fba1 467 error("Pin doese not support Analog to Digital Conversion");
Condo2k4 0:f0c00f67fba1 468 }
Condo2k4 0:f0c00f67fba1 469
Condo2k4 0:f0c00f67fba1 470 int adcIndex = adc >> ADC_INSTANCE_SHIFT, adcGroup = 0, adcChannel = adc & 0xF;
Condo2k4 0:f0c00f67fba1 471 prepareADC(adcIndex, adcGroup, adcChannel);
Condo2k4 0:f0c00f67fba1 472
Condo2k4 0:f0c00f67fba1 473 switch(prepareDMA(destination, destSize, dmaChannel, adcIndex, adcGroup, true)) {
Condo2k4 0:f0c00f67fba1 474 case kStatus_EDMA_QueueFull:
Condo2k4 0:f0c00f67fba1 475 case kStatus_EDMA_Busy:
Condo2k4 0:f0c00f67fba1 476 return E_DMA_IN_USE;
Condo2k4 0:f0c00f67fba1 477 default:
Condo2k4 0:f0c00f67fba1 478 break;
Condo2k4 0:f0c00f67fba1 479 }
Condo2k4 0:f0c00f67fba1 480
Condo2k4 0:f0c00f67fba1 481 int divider, modulus; bool useMult;
Condo2k4 0:f0c00f67fba1 482 calcClockDiv(sampleFrequency, divider, useMult, modulus);
Condo2k4 0:f0c00f67fba1 483 preparePDB(divider, useMult, modulus, adcIndex, adcGroup);
Condo2k4 0:f0c00f67fba1 484
Condo2k4 0:f0c00f67fba1 485 _bufSize = destSize;
Condo2k4 0:f0c00f67fba1 486 _callback = callback;
Condo2k4 0:f0c00f67fba1 487
Condo2k4 0:f0c00f67fba1 488 PDB_DoSoftwareTrigger(PDB0);
Condo2k4 0:f0c00f67fba1 489
Condo2k4 0:f0c00f67fba1 490 return SUCCESS;
Condo2k4 0:f0c00f67fba1 491 }
Condo2k4 0:f0c00f67fba1 492
Condo2k4 0:f0c00f67fba1 493 void terminateAsyncRead() {
Condo2k4 0:f0c00f67fba1 494 PDB_Enable(PDB0, false);
Condo2k4 0:f0c00f67fba1 495 EDMA_AbortTransfer(&_handle);
Condo2k4 0:f0c00f67fba1 496 _asyncReadActive = false;
Condo2k4 0:f0c00f67fba1 497 }
Condo2k4 0:f0c00f67fba1 498