Junichi Katsu
/
LineFollow2
ライントレーサPD制御 ロボット製作セミナー演習ex
HighSpeedAnalogIn/HighSpeedAnalogIn.cpp
- Committer:
- jksoft
- Date:
- 2013-08-10
- Revision:
- 0:b5d91230ff3c
File content as of revision 0:b5d91230ff3c:
#include "HighSpeedAnalogIn.h" HighSpeedAnalogIn *HighSpeedAnalogIn::instance; int HighSpeedAnalogIn::refcnt = 0; HighSpeedAnalogIn::HighSpeedAnalogIn(PinName pin0, PinName pin1, PinName pin2, PinName pin3, PinName pin4, PinName pin5) { refcnt++; if (refcnt > 1) { error("Please do not use over an object."); } static const int sample_rate = 200000; static const int cclk_div = 1; int adc_clk_freq = CLKS_PER_SAMPLE * sample_rate; int m = (LPC_SC->PLL0CFG & 0xFFFF) + 1; int n = (LPC_SC->PLL0CFG >> 16) + 1; int cclkdiv = LPC_SC->CCLKCFG + 1; int Fcco = (2 * m * XTAL_FREQ) / n; int cclk = Fcco / cclkdiv; LPC_SC->PCONP |= (1 << 12); LPC_SC->PCLKSEL0 &= ~(0x3 << 24); switch (cclk_div) { case 1: LPC_SC->PCLKSEL0 |= 0x1 << 24; break; case 2: LPC_SC->PCLKSEL0 |= 0x2 << 24; break; case 4: LPC_SC->PCLKSEL0 |= 0x0 << 24; break; case 8: LPC_SC->PCLKSEL0 |= 0x3 << 24; break; default: fprintf(stderr, "Warning: ADC CCLK clock divider must be 1, 2, 4 or 8. %u supplied.\n", cclk_div); fprintf(stderr, "Defaulting to 1.\n"); LPC_SC->PCLKSEL0 |= 0x1 << 24; break; } int pclk = cclk / cclk_div; int clock_div = pclk / adc_clk_freq; if (clock_div > 0xFF) { fprintf(stderr, "Warning: Clock division is %u which is above 255 limit. Re-Setting at limit.\n", clock_div); clock_div = 0xFF; } if (clock_div == 0) { fprintf(stderr, "Warning: Clock division is 0. Re-Setting to 1.\n"); clock_div = 1; } int _adc_clk_freq = pclk / clock_div; if (_adc_clk_freq > MAX_ADC_CLOCK) { fprintf(stderr, "Warning: Actual ADC sample rate of %u which is above %u limit\n", _adc_clk_freq / CLKS_PER_SAMPLE, MAX_ADC_CLOCK / CLKS_PER_SAMPLE); int max_div = 1; while ((pclk / max_div) > MAX_ADC_CLOCK) { max_div++; } fprintf(stderr, "Maximum recommended sample rate is %u\n", (pclk / max_div) / CLKS_PER_SAMPLE); } LPC_ADC->ADCR = ((clock_div - 1) << 8) | (1 << 21); LPC_ADC->ADCR &= ~0xFF; for (int i = 0; i < 8; i++) { _adc_data[i] = 0; } // Attach IRQ instance = this; NVIC_SetVector(ADC_IRQn, (uint32_t)&static_adcisr); // Disable global interrupt LPC_ADC->ADINTEN &= ~0x100; // Clock frequency. printf("Clock frequency:%d\n", _adc_clk_freq); // Actual sampling rate. printf("Actual sampling rate:%d\n", _adc_clk_freq / CLKS_PER_SAMPLE); int tmp = LPC_ADC->ADCR & ~(0x0F << 24); tmp |= ((0x0 & 7) << 24) | ((0x0 & 1) << 27); LPC_ADC->ADCR = tmp; LPC_ADC->ADCR |= (1 << 16); if (pin0 != NC) setup(pin0, 1); if (pin1 != NC) setup(pin1, 1); if (pin2 != NC) setup(pin2, 1); if (pin3 != NC) setup(pin3, 1); if (pin4 != NC) setup(pin4, 1); if (pin5 != NC) setup(pin5, 1); interrupt_state(pin0, 1); } HighSpeedAnalogIn::~HighSpeedAnalogIn() { } void HighSpeedAnalogIn::static_adcisr(void) { instance->adcisr(); } void HighSpeedAnalogIn::adcisr(void) { uint32_t stat = LPC_ADC->ADSTAT; // Scan channels for over-run or done and update array if (stat & 0x0101) _adc_data[0] = LPC_ADC->ADDR0; if (stat & 0x0202) _adc_data[1] = LPC_ADC->ADDR1; if (stat & 0x0404) _adc_data[2] = LPC_ADC->ADDR2; if (stat & 0x0808) _adc_data[3] = LPC_ADC->ADDR3; if (stat & 0x1010) _adc_data[4] = LPC_ADC->ADDR4; if (stat & 0x2020) _adc_data[5] = LPC_ADC->ADDR5; if (stat & 0x4040) _adc_data[6] = LPC_ADC->ADDR6; if (stat & 0x8080) _adc_data[7] = LPC_ADC->ADDR7; } int HighSpeedAnalogIn::get_channel(PinName pin) { int ch; switch (pin) { case p15:// =p0.23 of LPC1768 ch = 0; break; case p16:// =p0.24 of LPC1768 ch = 1; break; case p17:// =p0.25 of LPC1768 ch = 2; break; case p18:// =p0.26 of LPC1768 ch = 3; break; case p19:// =p1.30 of LPC1768 ch = 4; break; case p20:// =p1.31 of LPC1768 ch = 5; break; default: ch = 0; break; } return ch; } uint32_t HighSpeedAnalogIn::get_data(PinName pin) { // If in burst mode and at least one interrupt enabled then // take all values from _adc_data if (LPC_ADC->ADINTEN & 0x3F) { return (_adc_data[get_channel(pin)]); } else { // Return current register value or last value from interrupt switch (pin) { case p15:// =p0.23 of LPC1768 return ((LPC_ADC->ADINTEN & 0x01) ? _adc_data[0] : LPC_ADC->ADDR0); case p16:// =p0.24 of LPC1768 return ((LPC_ADC->ADINTEN & 0x02) ? _adc_data[1] : LPC_ADC->ADDR1); case p17:// =p0.25 of LPC1768 return ((LPC_ADC->ADINTEN & 0x04) ? _adc_data[2] : LPC_ADC->ADDR2); case p18:// =p0.26 of LPC1768: return ((LPC_ADC->ADINTEN & 0x08) ? _adc_data[3] : LPC_ADC->ADDR3); case p19:// =p1.30 of LPC1768 return ((LPC_ADC->ADINTEN & 0x10) ? _adc_data[4] : LPC_ADC->ADDR4); case p20:// =p1.31 of LPC1768 return ((LPC_ADC->ADINTEN & 0x20) ? _adc_data[5] : LPC_ADC->ADDR5); default: return 0; } } } // Enable or disable an HighSpeedAnalogIn pin void HighSpeedAnalogIn::setup(PinName pin, int state) { int ch = get_channel(pin); if ((state & 1) == 1) { switch (pin) { case p15:// =p0.23 of LPC1768 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14); LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 14; LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14); LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 14; break; case p16:// =p0.24 of LPC1768 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16); LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 16; LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16); LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 16; break; case p17:// =p0.25 of LPC1768 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18); LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 18; LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18); LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 18; break; case p18:// =p0.26 of LPC1768: LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20); LPC_PINCON->PINSEL1 |= (unsigned int)0x1 << 20; LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20); LPC_PINCON->PINMODE1 |= (unsigned int)0x2 << 20; break; case p19:// =p1.30 of LPC1768 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28); LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 28; LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28); LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 28; break; case p20:// =p1.31 of LPC1768 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30); LPC_PINCON->PINSEL3 |= (unsigned int)0x3 << 30; LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30); LPC_PINCON->PINMODE3 |= (unsigned int)0x2 << 30; break; default: error("Invalid pin."); break; } // Select channel LPC_ADC->ADCR |= (1 << ch); } else { switch (pin) { case p15://=p0.23 of LPC1768 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 14); LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 14); break; case p16://=p0.24 of LPC1768 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 16); LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 16); break; case p17://=p0.25 of LPC1768 LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 18); LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 18); break; case p18://=p0.26 of LPC1768: LPC_PINCON->PINSEL1 &= ~((unsigned int)0x3 << 20); LPC_PINCON->PINMODE1 &= ~((unsigned int)0x3 << 20); break; case p19://=p1.30 of LPC1768 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 28); LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 28); break; case p20://=p1.31 of LPC1768 LPC_PINCON->PINSEL3 &= ~((unsigned int)0x3 << 30); LPC_PINCON->PINMODE3 &= ~((unsigned int)0x3 << 30); break; default: error("Invalid pin."); break; } LPC_ADC->ADCR &= ~(1 << ch); } } void HighSpeedAnalogIn::interrupt_state(PinName pin, int state) { int ch = get_channel(pin); if (state == 1) { LPC_ADC->ADINTEN &= ~0x100; LPC_ADC->ADINTEN |= 1 << ch; /* Enable the HighSpeedAnalogIn Interrupt */ NVIC_EnableIRQ(ADC_IRQn); } else { LPC_ADC->ADINTEN &= ~(1 << ch); //Disable interrrupt if no active pins left if ((LPC_ADC->ADINTEN & 0xFF) == 0) NVIC_DisableIRQ(ADC_IRQn); } } float HighSpeedAnalogIn::read(PinName pin) { /* * Reset DONE and OVERRUN. * * bit 31 : DONE * bit 30 : OVERRUN */ _adc_data[get_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30)); return (float)((get_data(pin) >> 4) & 0xFFF) / (float)0xFFF; } unsigned short HighSpeedAnalogIn::read_u16(PinName pin) { /* * Reset DONE and OVERRUN. * * bit 31 : DONE * bit 30 : OVERRUN */ _adc_data[get_channel(pin)] &= ~(((uint32_t)0x01 << 31) | ((uint32_t)0x01 << 30)); return ((get_data(pin) >> 4) & 0xFFF); }