YAHAL
Yet Another Hardware Abstraction Library
Loading...
Searching...
No Matches
spi_msp432.cpp
1// ---------------------------------------------
2// This file is part of
3// _ _ __ _ _ __ __
4// ( \/ ) /__\ ( )_( ) /__\ ( )
5// \ / /(__)\ ) _ ( /(__)\ )(__
6// (__)(__)(__)(_) (_)(__)(__)(____)
7//
8// Yet Another HW Abstraction Library
9// Copyright (C) Andreas Terstegge
10// BSD Licensed (see file LICENSE)
11//
12// ---------------------------------------------
13//
14// The STE line is never used in HW mode, because
15// STE is deactivated after every byte, which is
16// not appropriate for most applications. We always
17// pass in a CS gpio pin, which might be used by
18// higher layers or automatically in this driver.
19
20#include <cassert>
21#include "spi_msp432.h"
22#include "irq_dispatcher.h"
23#include "msp.h"
24
25// If existing, use the global SubsystemMasterClock. If not, use our own
26// copy of the SystemCoreClock, assuming that MCLK equals SMCLK ...
27uint32_t SPI_CLK = SystemCoreClock;
28extern uint32_t SubsystemMasterClock __attribute__((weak,alias("SPI_CLK")));
29
30
31function<void(uint8_t)> spi_msp432::_intHandler[8];
32
33spi_msp432::spi_msp432(EUSCI_A_SPI_Type *mod, gpio_interface & cs,
34 const bool spi_master, uint16_t mode) :
35 _initialized(false), _master(spi_master), _generate_CS(true),
36 _EUSCI_CTLW0(mod->CTLW0), _EUSCI_BRW (mod->BRW),
37 _EUSCI_STATW(mod->STATW), _EUSCI_RXBUF(mod->RXBUF),
38 _EUSCI_TXBUF(mod->TXBUF), _EUSCI_IE (mod->IE),
39 _EUSCI_IFG (mod->IFG), _EUSCI_IV (mod->IV),
40 _mode(mode), _cs(cs)
41{
42 // Link in IRQ handlers
44 irq_dispatcher::link_in();
45
46 // Configure hardware characteristics of the 4 A-type modules
48 if (mod == EUSCI_A0_SPI) {
49 _clk.setGpio (PORT_PIN(1, 1));
50 _miso.setGpio(PORT_PIN(1, 2));
51 _mosi.setGpio(PORT_PIN(1, 3));
52 _irq = EUSCIA0_IRQn;
53 } else if (mod == EUSCI_A1_SPI) {
54 _clk.setGpio (PORT_PIN(2, 1));
55 _miso.setGpio(PORT_PIN(2, 2));
56 _mosi.setGpio(PORT_PIN(2, 3));
57 _irq = EUSCIA1_IRQn;
58 } else if (mod == EUSCI_A2_SPI) {
59 _clk.setGpio (PORT_PIN(3, 1));
60 _miso.setGpio(PORT_PIN(3, 2));
61 _mosi.setGpio(PORT_PIN(3, 3));
62 _irq = EUSCIA2_IRQn;
63 } else if (mod == EUSCI_A3_SPI) {
64 _clk.setGpio (PORT_PIN(9, 5));
65 _miso.setGpio(PORT_PIN(9, 6));
66 _mosi.setGpio(PORT_PIN(9, 7));
67 _irq = EUSCIA3_IRQn;
68 }
69 else assert(false);
70}
71
72spi_msp432::spi_msp432(EUSCI_B_SPI_Type *mod, gpio_interface & cs,
73 const bool spi_master, uint16_t mode) :
74 _initialized(false), _master(spi_master), _generate_CS(true),
75 _EUSCI_CTLW0(mod->CTLW0), _EUSCI_BRW (mod->BRW),
76 _EUSCI_STATW(mod->STATW), _EUSCI_RXBUF(mod->RXBUF),
77 _EUSCI_TXBUF(mod->TXBUF), _EUSCI_IE (mod->IE),
78 _EUSCI_IFG (mod->IFG), _EUSCI_IV (mod->IV),
79 _mode(mode), _cs(cs)
80{
81 // Configure hardware characteristics of the 4 B-type modules
83 if (mod == EUSCI_B0_SPI) {
84 _clk.setGpio (PORT_PIN(1, 5));
85 _miso.setGpio(PORT_PIN(1, 7));
86 _mosi.setGpio(PORT_PIN(1, 6));
87 _irq = EUSCIB0_IRQn;
88 } else if (mod == EUSCI_B1_SPI) {
89 _clk.setGpio (PORT_PIN(6, 3));
90 _miso.setGpio(PORT_PIN(6, 5));
91 _mosi.setGpio(PORT_PIN(6, 4));
92 _irq = EUSCIB1_IRQn;
93 } else if (mod == EUSCI_B2_SPI) {
94 _clk.setGpio( PORT_PIN(3, 5));
95 _miso.setGpio(PORT_PIN(3, 7));
96 _mosi.setGpio(PORT_PIN(3, 6));
97 _irq = EUSCIB2_IRQn;
98 } else if (mod == EUSCI_B3_SPI) {
99 _clk.setGpio( PORT_PIN(10, 1));
100 _miso.setGpio(PORT_PIN(10, 3));
101 _mosi.setGpio(PORT_PIN(10, 2));
102 _irq = EUSCIB3_IRQn;
103 }
104 else assert(false);
105}
106
107spi_msp432::~spi_msp432() {
108 // Wait for pending operations
110 while (_EUSCI_STATW & EUSCI_A_STATW_BUSY);
111
112 // Reset CTLW0 register to default values
113 // (EUSCI_A is in reset state)
115 _EUSCI_CTLW0 = EUSCI_A_CTLW0_SWRST;
116}
117
118void spi_msp432::initialize() {
119
120 // Configure the digital CLK, MISO and MOSI pins
122 _clk.setSEL(1);
123 _clk.setMode (_master ? GPIO::OUTPUT : GPIO::INPUT);
124 _miso.setSEL(1);
125 _miso.setMode(_master ? GPIO::INPUT : GPIO::OUTPUT);
126 _mosi.setSEL(1);
127 _mosi.setMode(_master ? GPIO::OUTPUT : GPIO::INPUT);
128
129 // Configure CS pin
131 _cs.gpioMode(_master ? GPIO::OUTPUT | GPIO::INIT_HIGH : GPIO::INPUT);
132
133 // Reset CTLW0 register to default values
134 // (EUSCI is in reset state)
136 _EUSCI_CTLW0 = EUSCI_A_CTLW0_SWRST;
137
138 // Configure SPI port
140 if (_master) {
141 _mode |= EUSCI_A_CTLW0_MST; // master mode
142 }
143 _mode |= EUSCI_A_CTLW0_SYNC | // always synchronous mode
144 EUSCI_A_CTLW0_STEM; // always STE as CS-line
145 // always 3 wire mode!
146 _EUSCI_CTLW0 |= _mode;
147
148 // Disable interrupts default
150 _EUSCI_IE = 0;
151
152 // Finally enable EUSCI module
154 _EUSCI_CTLW0 &= ~EUSCI_A_CTLW0_SWRST;
155
156 // Set 'initialized' flag
158 _initialized = true;
159}
160
161int16_t spi_msp432::spiTxRx(const uint8_t *txbuf, uint8_t *rxbuf, uint16_t len)
162{
163 if (!_initialized) initialize();
164 if (_master) {
165 // Activate CS line
166 if (_generate_CS) _cs.gpioWrite(LOW);
167 } else {
168 // Wait for CS to be LOW
169 while(_cs.gpioRead()) ;
170 }
171
172 _EUSCI_IFG = 0;
173 _EUSCI_STATW = 0; // TODO: Works only in Reset mode ...
174 rxbuf[0] = _EUSCI_RXBUF;
175
176 for (int i = 0; i < len; ++i)
177 {
178 // Transfer single char to TX buffer
179 _EUSCI_TXBUF = (uint16_t) (txbuf[i]);
180 // Receive single char from RX buffer
181 while( !(_EUSCI_IFG & EUSCI_A_IFG_RXIFG));
182 rxbuf[i] = (uint8_t)(_EUSCI_RXBUF);
183 // Wait until last data was sent
184 while (!(_EUSCI_IFG & EUSCI_A_IFG_TXIFG));
185 }
186
187 if (_master) {
188 // De-activate CS line
189 if (_generate_CS) _cs.gpioWrite(HIGH);
190 } else {
191 // Wait for CS to be HIGH
192 while(!_cs.gpioRead()) ;
193 }
194 return len;
195}
196
197int16_t spi_msp432::spiTx(const uint8_t *txbuf, uint16_t len) {
198 if (!_initialized) initialize();
199 if (_master) {
200 // Activate CS line
201 if (_generate_CS) _cs.gpioWrite(LOW);
202 } else {
203 // Wait for CS to be LOW
204 while(_cs.gpioRead()) ;
205 }
206
207 _EUSCI_IFG = 0;
208 _EUSCI_STATW = 0; // TODO: Works only in Reset mode ...
209
210 for (int i = 0; i < len; ++i)
211 {
212 // Transfer single char to TX buffer
213 _EUSCI_TXBUF = (uint16_t) (txbuf[i]);
214 // Wait until last data was sent
215 while (!(_EUSCI_IFG & EUSCI_A_IFG_TXIFG));
216 }
217
218 if (_master) {
219 // De-activate CS line
220 if (_generate_CS) _cs.gpioWrite(HIGH);
221 } else {
222 // Wait for CS to be HIGH
223 while(!_cs.gpioRead()) ;
224 }
225 return len;
226}
227
228int16_t spi_msp432::spiRx(uint8_t tx_byte, uint8_t *rxbuf, uint16_t len) {
229 if (!_initialized) initialize();
230 if (_master) {
231 // Activate CS line
232 if (_generate_CS) _cs.gpioWrite(LOW);
233 } else {
234 // Wait for CS to be LOW
235 while(_cs.gpioRead()) ;
236 }
237
238 _EUSCI_IFG = 0;
239 _EUSCI_STATW = 0; // TODO: Works only in Reset mode ...
240 rxbuf[0] = _EUSCI_RXBUF;
241
242 for (int i = 0; i < len; ++i)
243 {
244 // Transfer single char to TX buffer
245 _EUSCI_TXBUF = (uint16_t) (tx_byte);
246 // Receive single char from RX buffer
247 while( !(_EUSCI_IFG & EUSCI_A_IFG_RXIFG));
248 rxbuf[i] = (uint8_t)(_EUSCI_RXBUF);
249 // Wait until last data was sent
250 while (!(_EUSCI_IFG & EUSCI_A_IFG_TXIFG));
251 }
252
253 if (_master) {
254 // De-activate CS line
255 if (_generate_CS) _cs.gpioWrite(HIGH);
256 } else {
257 // Wait for CS to be HIGH
258 while(!_cs.gpioRead()) ;
259 }
260 return len;
261}
262
263
264void spi_msp432::setSpeed(uint32_t baud)
265{
266 if (!_initialized) initialize();
267 _EUSCI_BRW = SubsystemMasterClock / baud;
268}
269
270void spi_msp432::generateCS(bool val)
271{
272 if (!_initialized) initialize();
273 _generate_CS = val;
274}
275
276void spi_msp432::setCS(bool val) {
277 if (!_initialized) initialize();
278 _cs.gpioWrite(val);
279}
280
281void spi_msp432::spiAttachRxIrq(function<void(uint8_t data)> f) {
282 // Register handler
283 _intHandler[_irq-16] = f;
284 // Enable receive IRQ
285 _EUSCI_IE = EUSCI_A_IE_RXIE;
286 // Enable IRQ in NVIC
287 NVIC_EnableIRQ(_irq);
288}
289
290
291extern "C"
292{
293
294void EUSCIA0_SPI_IRQHandler(void)
295{
296 spi_msp432::_intHandler[0]( EUSCI_A0->RXBUF );
297}
298
299void EUSCIA1_SPI_IRQHandler(void)
300{
301 spi_msp432::_intHandler[1]( EUSCI_A1->RXBUF );
302}
303
304void EUSCIA2_SPI_IRQHandler(void)
305{
306 spi_msp432::_intHandler[2]( EUSCI_A2->RXBUF );
307}
308
309void EUSCIA3_SPI_IRQHandler(void)
310{
311 spi_msp432::_intHandler[3]( EUSCI_A3->RXBUF );
312}
313
314void EUSCIB0_SPI_IRQHandler(void)
315{
316 spi_msp432::_intHandler[4]( EUSCI_B0->RXBUF );
317}
318
319void EUSCIB1_SPI_IRQHandler(void)
320{
321 spi_msp432::_intHandler[5]( EUSCI_B1->RXBUF );
322}
323
324void EUSCIB2_SPI_IRQHandler(void)
325{
326 spi_msp432::_intHandler[6]( EUSCI_B2->RXBUF );
327}
328
329void EUSCIB3_SPI_IRQHandler(void)
330{
331 spi_msp432::_intHandler[7]( EUSCI_B3->RXBUF );
332}
333
334} // extern "C"
#define EUSCI_A_CTLW0_STEM
#define EUSCI_A_CTLW0_MST
#define EUSCI_A_IFG_RXIFG
#define EUSCI_A_STATW_BUSY
#define EUSCI_A_IFG_TXIFG
#define EUSCI_A_CTLW0_SWRST
#define EUSCI_A_CTLW0_SYNC
#define EUSCI_A_IE_RXIE
void __attribute__((noreturn))(*rom_reset_usb_boot_fn)(uint32_t
Reboot the device into BOOTSEL mode.
Definition bootrom.h:66