YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
adc14_msp432.cpp
1/*
2 * gpio_msp432.cpp
3 *
4 * Created on: 29.02.2016
5 * Author: Andreas Terstegge
6 */
7
8#include <cassert>
9#include "adc14_msp432.h"
10#include "gpio_msp432.h"
11#include "msp.h"
12
13adc14_msp432 adc14_msp432::inst;
14
15adc14_msp432::adc14_msp432() {
16 adcStopScan();
17 // Set up the channel -> register mapping
18 for(uint8_t channel = 0; channel < 24; ++channel) {
19 ADC14->MCTL[channel] = channel;
20 ADC14->MCTL[channel] |= ADC14_MCTLN_VRSEL_0;
21 }
22 // Initialize resolution
23 _current_mode = 0;
24
25 // set up control register 0
26 uint32_t ctl0 = 0;
27 ctl0 |= ADC14_CTL0_ON; // switch on ADC module
28 ctl0 |= ADC14_CTL0_SSEL__SMCLK; // Use SMCLK
29 ctl0 |= ADC14_CTL0_DIV__1; // clock divider is 1
30 ctl0 |= ADC14_CTL0_PDIV__4; // clock pre-divider is 4
31 ctl0 |= ADC14_CTL0_SHS_0; // use ADC14SC bit as sample/hold trigger
32 ctl0 |= ADC14_CTL0_SHP; // use sample/hold counter
33 ctl0 |= ADC14_CTL0_SHT0__64; // 64 clocks for sample/hold
34 ctl0 |= ADC14_CTL0_SHT1__64; // 64 clocks for sample/hold
35 ADC14->CTL0 = ctl0;
36 // set up control register 1
37 ADC14->CTL1 |= ADC14_CTL1_PWRMD_0;
38 // Initialize and disable interrupts
39 ADC14->IER0 = 0;
40 ADC14->IER1 = 0;
41 NVIC_EnableIRQ(ADC14_IRQn);
42}
43
44void adc14_msp432::adcMode(uint8_t channel, uint16_t mode) {
45 assert(channel < 24);
46 _modes[channel] = mode;
47 uint16_t port_pin = (5 << 3) + 5; // A0 is on P5.5
48 if (channel > 13)
49 port_pin = (6 << 3) + 1 + 14; // A14 is on P6.1
50 if (channel > 15)
51 port_pin = (9 << 3) + 1 + 16; // A16 is on P9.1
52 // Calculate the port and pin for the given ADC channel
53 port_pin -= channel;
54 uint8_t port = port_pin >> 3;
55 uint8_t pin = port_pin & 0x7;
56 // Select ADC mode
57 gpio_msp432 gpio(PORT_PIN(port, pin));
58 gpio.setSEL(3);
59}
60
61adc_mode_t adc14_msp432::getMode(uint8_t channel) {
62 assert(channel < 24);
63 return _modes[channel];
64}
65
66uint16_t adc14_msp432::adcReadRaw(uint8_t channel) {
67 assert(channel < 24);
68 // set resolution
69 if (_current_mode !=_modes[channel]) {
70 set_resolution( _modes[channel] );
71 } else {
72 adcStopScan();
73 }
74 // set up start channel
75 ADC14->CTL1 &= ~ADC14_CTL1_CSTARTADD_MASK;
76 ADC14->CTL1 |= (channel << ADC14_CTL1_CSTARTADD_OFS);
77 // set single channel / single conversion
78 ADC14->CTL0 &= ~ADC14_CTL0_CONSEQ_MASK;
79 ADC14->CTL0 |= ADC14_CTL0_CONSEQ_0;
80 // start the conversion process
81 ADC14->CTL0 |= (ADC14_CTL0_ENC | ADC14_CTL0_SC);
82 // wait until active conversion is done
83 while (BITBAND_PERI(ADC14->CTL0, ADC14_CTL0_BUSY_OFS));
84 return ADC14->MEM[channel];
85}
86
87float adc14_msp432::adcReadVoltage(uint8_t channel) {
88 return rawToVoltage(channel, adcReadRaw(channel));
89}
90
91float adc14_msp432::rawToVoltage(uint8_t channel, uint16_t raw) {
92 float voltage = 3.3f * (float)raw;
93 switch(_modes[channel]) {
94 case ADC::ADC_8_BIT : voltage /= 255.0f; break;
95 case ADC::ADC_10_BIT: voltage /= 1023.0f; break;
96 case ADC::ADC_12_BIT: voltage /= 4095.0f; break;
97 case ADC::ADC_14_BIT: voltage /= 16383.0f; break;
98 default: assert(false);
99 }
100 return voltage;
101}
102
103void adc14_msp432::adcSetupScan(uint16_t mode) {
104 adcStopScan();
105 if (_current_mode != mode) {
106 set_resolution(mode);
107 }
108}
109
110void adc14_msp432::adcStartScan(uint8_t start, uint8_t end) {
111 assert((start < 24) && (end < 24) && (start <= end));
112 adcStopScan();
113 // set up start channel
114 ADC14->CTL1 &= ~ADC14_CTL1_CSTARTADD_MASK;
115 ADC14->CTL1 |= (start << ADC14_CTL1_CSTARTADD_OFS);
116 // set up end channel
117 ADC14->MCTL[end] |= ADC14_MCTLN_EOS;
118 // repeat sequence of channels
119 ADC14->CTL0 |= ADC14_CTL0_CONSEQ_3;
120 // enable automatic multiple samples
121 ADC14->CTL0 |= ADC14_CTL0_MSC;
122 // start the automatic scan process
123 ADC14->CTL0 |= (ADC14_CTL0_ENC | ADC14_CTL0_SC);
124}
125
126void adc14_msp432::adcStopScan() {
127 // disable conversions
128 if (BITBAND_PERI(ADC14->CTL0, ADC14_CTL0_ENC_OFS)) {
129 BITBAND_PERI(ADC14->CTL0, ADC14_CTL0_ENC_OFS) = 0;
130 // make sure the ENC low pulse has a minimum duration
131 for (int i = 0; i < 1000; ++i) ;
132 }
133}
134
135uint16_t adc14_msp432::adcReadScan(uint8_t channel) {
136 assert(channel < 24);
137 return ADC14->MEM[channel];
138}
139
140void adc14_msp432::attachScanIrq(uint8_t channel,
141 void (*handler)(uint16_t chan, uint16_t val) ) {
142 assert(channel < 24);
143 adcStopScan();
144 // store handler function
145 _irqHandlers[channel] = handler;
146 // enable the channel irq
147 ADC14->IER0 |= (1 << channel);
148}
149
150void adc14_msp432::attachWinIrq(uint8_t channel,
151 void (*handler)(uint16_t val, uint16_t mode),
152 uint16_t low, uint16_t high,
153 uint16_t mode) {
154 assert(channel < 24);
155 // Window irqs are only allowed on ONE channel!
156 assert(!(ADC14->IER1 & (ADC14_IER1_HIIE |
158 ADC14_IER1_INIE) ));
159
160 adcStopScan();
161 _irqWinHandler = handler;
162 _irqWinMode = mode;
163 _irqWinChannel = channel;
164 // set and enable window
165 ADC14->LO0 = low;
166 ADC14->HI0 = high;
167 ADC14->MCTL[channel] |= ADC14_MCTLN_WINC;
168 // enable the window irqs
169 if (mode & ADC::ABOVE_HIGH) ADC14->IER1 |= ADC14_IER1_HIIE;
170 if (mode & ADC::BELOW_LOW ) ADC14->IER1 |= ADC14_IER1_LOIE;
171 if (mode & ADC::WITHIN_WIN) ADC14->IER1 |= ADC14_IER1_INIE;
172}
173
174void adc14_msp432::set_resolution(uint16_t mode) {
175 adcStopScan();
176 ADC14->CTL1 &= ~ADC14_CTL1_RES_MASK;
177 switch(mode) {
178 case ADC::ADC_8_BIT:
179 ADC14->CTL1 |= ADC14_CTL1_RES__8BIT;
180 _current_mode = ADC::ADC_8_BIT;
181 break;
182 case ADC::ADC_10_BIT:
183 ADC14->CTL1 |= ADC14_CTL1_RES__10BIT;
184 _current_mode = ADC::ADC_10_BIT;
185 break;
186 case ADC::ADC_12_BIT:
187 ADC14->CTL1 |= ADC14_CTL1_RES__12BIT;
188 _current_mode = ADC::ADC_12_BIT;
189 break;
190 case ADC::ADC_14_BIT:
191 ADC14->CTL1 |= ADC14_CTL1_RES__14BIT;
192 _current_mode = ADC::ADC_14_BIT;
193 break;
194 default:
195 assert(false);
196 }
197}
198
199void adc14_msp432::handleIrq(uint32_t iv) {
200 if (iv < 0x000c) {
201 // A window interrupt has occurred
203 uint16_t mode = 0;
204 adcStopScan();
205 ADC14->MCTL[_irqWinChannel] &= ~ADC14_MCTLN_WINC;
206 ADC14->IER1 &= ~(ADC14_IER1_HIIE |
209 ADC14->CLRIFGR1 |= (ADC14_CLRIFGR1_CLRHIIFG |
212 switch(iv) {
213 case 0x6: mode = ADC::ABOVE_HIGH; break;
214 case 0x8: mode = ADC::BELOW_LOW; break;
215 case 0xa: mode = ADC::WITHIN_WIN; break;
216 }
217 if (_irqWinHandler)
218 _irqWinHandler(ADC14->MEM[_irqWinChannel], mode);
219 // re-start the automatic scan process
220 ADC14->CTL0 |= (ADC14_CTL0_ENC | ADC14_CTL0_SC);
221 } else {
222 // A channel interrupt has occurred
224 iv = (iv >> 1) - 6;
225 if (_irqHandlers[iv]) _irqHandlers[iv](iv, ADC14->MEM[iv]);
226 }
227}
228
229extern "C" {
230
231void ADC14_IRQHandler(void) {
232 uint32_t iv = ADC14->IV;
233 adc14_msp432::inst.handleIrq( iv );
234}
235
236} // extern "C"
237
#define ADC14_IER1_LOIE
#define ADC14_CTL0_PDIV__4
#define ADC14_CTL0_SHT1__64
#define ADC14_CTL1_RES__10BIT
#define ADC14_CTL0_DIV__1
#define ADC14_CTL0_ENC
#define ADC14_CTL1_RES__8BIT
#define ADC14_CLRIFGR1_CLRINIFG
#define ADC14_CTL0_SHS_0
#define ADC14_CTL0_SC
#define ADC14_CTL0_MSC
#define ADC14_CTL0_ON
#define ADC14_CTL0_CONSEQ_3
#define ADC14_CTL0_CONSEQ_0
#define ADC14_MCTLN_VRSEL_0
#define ADC14_IER1_INIE
#define ADC14_CTL0_SHT0__64
#define ADC14_CTL0_SHP
#define ADC14_CTL0_ENC_OFS
#define ADC14_CLRIFGR1_CLRLOIFG
#define ADC14_MCTLN_WINC
#define ADC14_CTL1_CSTARTADD_OFS
#define ADC14_CTL1_RES__14BIT
#define ADC14_MCTLN_EOS
#define ADC14_CTL1_PWRMD_0
#define ADC14_CLRIFGR1_CLRHIIFG
#define ADC14_CTL0_BUSY_OFS
#define ADC14_CTL1_RES__12BIT
#define ADC14_CTL0_SSEL__SMCLK
#define ADC14_IER1_HIIE