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

Dependents:   MoppyController

Committer:
Condo2k4
Date:
Wed May 24 11:57:48 2017 +0000
Revision:
2:754768be9b9a
Parent:
1:57441202d8d0
Fixes

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