Unverified Commit fc390815 authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

MSP430FR5994 ADC: add asynchronous backgorund readings on P3.0

parent 803f605e
Loading
Loading
Loading
Loading
Loading
+28 −1
Original line number Diff line number Diff line
@@ -6,18 +6,45 @@
#ifndef ADC_H
#define ADC_H

#include <stddef.h>
#include <stdint.h>

class ADC {
	private:
		ADC(ADC const &copy);

		uint16_t bufsize;
		uint16_t bufpos;
		uint16_t *buf16;
		uint8_t *buf8;
		volatile bool bufferFull;

	public:
		ADC() {}
		ADC() : bufsize(0), bufpos(0), buf16(NULL), buf8(NULL), bufferFull(false) {}

		float getTemp();
		float getVCC();
		uint16_t getReading();
		void startSampling(uint16_t *buf, uint16_t bufsize);
		void stopSampling();

		inline bool doneSampling()
		{
			if (bufferFull) {
				bufferFull = false;
				return true;
			}
			return false;
		}

		inline void storeReading(uint16_t value)
		{
			buf16[bufpos++] = value;
			bufpos %= bufsize;
			if (bufpos == 0) {
				bufferFull = true;
			}
		}
};

extern ADC adc;
+83 −1
Original line number Diff line number Diff line
@@ -9,6 +9,11 @@
#define CALADC12_12V_30C  *((unsigned int *)0x1A1A)
#define CALADC12_12V_85C  *((unsigned int *)0x1A1C)

/*
 * Obtain a single reading of the embedded temperature sensor, converted to °C.
 * Configures and enables ADC and voltage reference, reads the temperature, and then disables both.
 * This is a blocking function.
 */
float ADC::getTemp()
{
	float ret;
@@ -40,6 +45,12 @@ float ADC::getTemp()
	return ret;
}


/*
 * Obtain a single VCC reading, using the internal 2V voltage reference and the internal VCC/2 rail.
 * Configures and enables ADC and voltage reference, reads the temperature, and then disables both.
 * This is a blocking function.
 */
float ADC::getVCC()
{
	float ret;
@@ -70,10 +81,16 @@ float ADC::getVCC()
	return ret;
}


/*
 * Obtain a single 12-bit reading of A12 (P3.0), using AVCC / AVSS as references.
 * Configures and enables the ADC, reads a single value, and then disables the ADC again.
 * This is a blocking function.
 */
uint16_t ADC::getReading()
{
	ADC12CTL0 &= ~ADC12ENC; // disable ADC for configuration
	ADC12CTL0 = ADC12SHT0_8 | ADC12SHT1_8 | ADC12ON; // Sample & Hold: 64 ADC12CLK cycles; enable ADC
	ADC12CTL0 = ADC12SHT0_8 | ADC12SHT1_8 | ADC12ON; // Sample & Hold: 256 ADC12CLK cycles; enable ADC
	ADC12CTL1 = ADC12SHP; // MODOSC, no prescaler
	ADC12CTL2 = ADC12RES_2; // 12 bit resolution
	ADC12CTL3 = ADC12CSTARTADD_0; // store reading in ADCMEM0
@@ -99,4 +116,69 @@ uint16_t ADC::getReading()
	return ret;
}

/*
 * Obtain a serias of 12-bit readings of A12 (P3.0), using AVCC / AVSS as references.
 * Configures and enables the ADC, and then returns.
 */
void ADC::startSampling(uint16_t *buf, uint16_t bufsize)
{
	ADC12CTL0 &= ~ADC12ENC; // disable ADC for configuration
	ADC12CTL0 = ADC12SHT0_8 | ADC12SHT1_8 | ADC12MSC | ADC12ON; // Sample & Hold: 64 ADC12CLK cycles; multiple conversions; enable ADC

	/*
	 * Sample & Hold: 64 ADC12CLK cycles
	 * 8-bit reading: 10 ADC12CLK cycles
	 * → 74 ADC12CLK cycles per reading
	 * → ≈68 kHz sample rate at ≈5 MHz
	 * 216,216 Hz / 2048 == 106 Hz (close enough)
	 * → set prescalers to /2048 (or something close, anyways)
	 * ... lowest we can get with SMCLK ref is /512, that's fine too
	 * Also, we want repeated single-channel conversion.
	 */
	ADC12CTL1 = ADC12PDIV__64 | ADC12SHP | ADC12DIV_7 | ADC12SSEL_3 | ADC12CONSEQ_2;

	// 12 bit readings (14 clock cycles conversion time)
	// (10 bit → 12 cycles / 12 bit → 14 cycles)
	ADC12CTL2 = ADC12RES_2;

	// store each (consecutive) reading in ADCMEM1
	ADC12CTL3 = ADC12CSTARTADD_1;

	// use default reference (AVSS / AVCC) (only required if changed by some other runtime code beforehand)
	// read from A12 (P3.0)
	ADC12MCTL1 = ADC12INCH_12;

	// disable output driver and input schmitt triggers on P3.0 (A12)
	P3SEL0 |= BIT0;
	P3SEL1 |= BIT0;

	// raise an interrupt after each sample
	ADC12IER0 = ADC12IE1;
	ADC12IFGR0 = ADC12IFG1;

	// clear pending interrupts
	ADC12IV = 0;

	buf16 = buf;
	this->bufsize = bufsize;

	ADC12CTL0 |= ADC12ENC | ADC12SC;
}

void ADC::stopSampling()
{
	ADC12CTL0 &= ~ADC12ENC; // disable any conversion to allow ADC configuration
	ADC12CTL0 &= ~ADC12ON; // Turn off ADC
}

ADC adc;

#ifndef __acweaving
__attribute__((interrupt(ADC12_VECTOR))) void handle_adc_irq()
{
	if (ADC12IV == 0x00e) {
		// ADC12MEM1
		adc.storeReading(ADC12MEM1);
	}
}
#endif