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

Dependents:   MoppyController

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