-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmsp430fr413x_eusci_spi_standard_master.c
More file actions
433 lines (360 loc) · 14.4 KB
/
msp430fr413x_eusci_spi_standard_master.c
File metadata and controls
433 lines (360 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
//******************************************************************************
// MSP430FR413x Demo - eUSCI_B0, SPI 4-Wire Master multiple byte RX/TX
//
// Description: SPI master communicates to SPI slave sending and receiving
// 3 different messages of different length. SPI master will enter LPM0 mode
// while waiting for the messages to be sent/receiving using SPI interrupt.
// SPI Master will initially wait for a port interrupt in LPM0 mode before
// starting the SPI communication.
// ACLK = NA, MCLK = SMCLK = DCO 16MHz.
//
//
// MSP430FR4133
// -----------------
// /|\ | P1.1|-> Comms LED
// | | |
// ---|RST P5.4|-> Slave Reset (GPIO)
// | |
// | P5.2|-> Data Out (UCB0SIMO)
// | |
// Button ->|P1.3 P5.3|<- Data In (UCB0SOMI)
// Button LED <-|P1.0 |
// | P5.1|-> Serial Clock Out (UCB0CLK)
// | |
// | P5.0|-> Slave Chip Select (GPIO)
//
// Nima Eskandari and Ryan Meredith
// Texas Instruments Inc.
// November 2017
// Built with CCS V7.3
//******************************************************************************
#include <msp430.h>
#include <stdint.h>
//******************************************************************************
// Pin Config ******************************************************************
//******************************************************************************
#define SLAVE_RST_OUT P5OUT
#define SLAVE_RST_DIR P5DIR
#define SLAVE_RST_PIN BIT4
#define BUTTON_DIR P1DIR
#define BUTTON_OUT P1OUT
#define BUTTON_REN P1REN
#define BUTTON_PIN BIT3
#define BUTTON_IES P1IES
#define BUTTON_IE P1IE
#define BUTTON_IFG P1IFG
#define BUTTON_VECTOR PORT1_VECTOR
#define BUTTON_LED_OUT P1OUT
#define BUTTON_LED_DIR P1DIR
#define BUTTON_LED_PIN BIT0
#define COMMS_LED_OUT P1OUT
#define COMMS_LED_DIR P1DIR
#define COMMS_LED_PIN BIT1
#define SLAVE_CS_OUT P5OUT
#define SLAVE_CS_DIR P5DIR
#define SLAVE_CS_PIN BIT0
//******************************************************************************
// Example Commands ************************************************************
//******************************************************************************
#define DUMMY 0xFF
/* CMD_TYPE_X_SLAVE are example commands the master sends to the slave.
* The slave will send example SlaveTypeX buffers in response.
*
* CMD_TYPE_X_MASTER are example commands the master sends to the slave.
* The slave will initialize itself to receive MasterTypeX example buffers.
* */
#define CMD_TYPE_0_SLAVE 0
#define CMD_TYPE_1_SLAVE 1
#define CMD_TYPE_2_SLAVE 2
#define CMD_TYPE_0_MASTER 3
#define CMD_TYPE_1_MASTER 4
#define CMD_TYPE_2_MASTER 5
#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6
#define MAX_BUFFER_SIZE 20
/* MasterTypeX are example buffers initialized in the master, they will be
* sent by the master to the slave.
* SlaveTypeX are example buffers initialized in the slave, they will be
* sent by the slave to the master.
* */
uint8_t MasterType0 [TYPE_0_LENGTH] = {0x11};
uint8_t MasterType1 [TYPE_1_LENGTH] = {8, 9};
uint8_t MasterType2 [TYPE_2_LENGTH] = {'F', '4' , '1' , '9', '2', 'B'};
uint8_t SlaveType2 [TYPE_2_LENGTH] = {0};
uint8_t SlaveType1 [TYPE_1_LENGTH] = {0};
uint8_t SlaveType0 [TYPE_0_LENGTH] = {0};
//******************************************************************************
// General SPI State Machine ***************************************************
//******************************************************************************
typedef enum SPI_ModeEnum{
IDLE_MODE,
TX_REG_ADDRESS_MODE,
RX_REG_ADDRESS_MODE,
TX_DATA_MODE,
RX_DATA_MODE,
TIMEOUT_MODE
} SPI_Mode;
/* Used to track the state of the software state machine*/
SPI_Mode MasterMode = IDLE_MODE;
/* The Register Address/Command to use*/
uint8_t TransmitRegAddr = 0;
/* ReceiveBuffer: Buffer used to receive data in the ISR
* RXByteCtr: Number of bytes left to receive
* ReceiveIndex: The index of the next byte to be received in ReceiveBuffer
* TransmitBuffer: Buffer used to transmit data in the ISR
* TXByteCtr: Number of bytes left to transfer
* TransmitIndex: The index of the next byte to be transmitted in TransmitBuffer
* */
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
/* SPI Write and Read Functions */
/* For slave device, writes the data specified in *reg_data
*
* reg_addr: The register or command to send to the slave.
* Example: CMD_TYPE_0_MASTER
* *reg_data: The buffer to write
* Example: MasterType0
* count: The length of *reg_data
* Example: TYPE_0_LENGTH
* */
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count);
/* For slave device, read the data specified in slaves reg_addr.
* The received data is available in ReceiveBuffer
*
* reg_addr: The register or command to send to the slave.
* Example: CMD_TYPE_0_SLAVE
* count: The length of data to read
* Example: TYPE_0_LENGTH
* */
SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
void SendUCB0Data(uint8_t val);
void SendUCB0Data(uint8_t val)
{
while (!(UCB0IFG & UCTXIFG)); // USCI_B0 TX buffer ready?
UCB0TXBUF = val;
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
uint8_t copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex];
}
}
SPI_Mode SPI_Master_WriteReg(uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
//Copy register data to TransmitBuffer
CopyArray(reg_data, TransmitBuffer, count);
TXByteCtr = count;
RXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
SLAVE_CS_OUT &= ~(SLAVE_CS_PIN);
SendUCB0Data(TransmitRegAddr);
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
SLAVE_CS_OUT |= SLAVE_CS_PIN;
return MasterMode;
}
SPI_Mode SPI_Master_ReadReg(uint8_t reg_addr, uint8_t count)
{
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
RXByteCtr = count;
TXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
SLAVE_CS_OUT &= ~(SLAVE_CS_PIN);
SendUCB0Data(TransmitRegAddr);
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
SLAVE_CS_OUT |= SLAVE_CS_PIN;
return MasterMode;
}
//******************************************************************************
// Device Initialization *******************************************************
//******************************************************************************
void initSPI()
{
//Clock Polarity: The inactive state is high
//MSB First, 8-bit, Master, 3-pin mode, Synchronous
UCB0CTLW0 = UCSWRST; // **Put state machine in reset**
UCB0CTLW0 |= UCCKPL | UCMSB | UCSYNC
| UCMST | UCSSEL__SMCLK; // 3-pin, 8-bit SPI Slave
UCB0BRW = 0x20;
//UCB0MCTLW = 0;
UCB0CTLW0 &= ~UCSWRST; // **Initialize USCI state machine**
UCB0IE |= UCRXIE; // Enable USCI0 RX interrupt
}
void initGPIO()
{
//LEDs
COMMS_LED_DIR |= COMMS_LED_PIN;
COMMS_LED_OUT &= ~COMMS_LED_PIN;
BUTTON_LED_DIR |= BUTTON_LED_PIN;
BUTTON_LED_OUT &= ~BUTTON_LED_PIN;
// Configure SPI
P5SEL0 |= BIT1 | BIT2 | BIT3;
SLAVE_RST_DIR |= SLAVE_RST_PIN;
SLAVE_RST_OUT |= SLAVE_RST_PIN;
SLAVE_CS_DIR |= SLAVE_CS_PIN;
SLAVE_CS_OUT |= SLAVE_CS_PIN;
//Button to initiate transfer
BUTTON_DIR &= ~(BUTTON_PIN); // button input
BUTTON_OUT |= BUTTON_PIN; // button pull up
BUTTON_REN |= BUTTON_PIN; // button pull up/down resistor enable
BUTTON_IES |= BUTTON_PIN; // button Hi/lo edge
BUTTON_IFG &= ~BUTTON_PIN; // button IFG cleared
BUTTON_IE |= BUTTON_PIN; // button interrupt enabled
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings
PM5CTL0 &= ~LOCKLPM5;
}
void initClockTo16MHz()
{
// Configure one FRAM waitstate as required by the device datasheet for MCLK
// operation beyond 8MHz _before_ configuring the clock system.
FRCTL0 = FRCTLPW | NWAITS_1;
__bis_SR_register(SCG0); // disable FLL
CSCTL3 |= SELREF__REFOCLK; // Set REFO as FLL reference source
CSCTL0 = 0; // clear DCO and MOD registers
CSCTL1 &= ~(DCORSEL_7); // Clear DCO frequency select bits first
CSCTL1 |= DCORSEL_5; // Set DCO = 16MHz
CSCTL2 = FLLD_0 + 487; // set to fDCOCLKDIV = (FLLN + 1)*(fFLLREFCLK/n)
// = (487 + 1)*(32.768 kHz/1)
// = 16 MHz
__delay_cycles(3);
__bic_SR_register(SCG0); // enable FLL
while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // FLL locked
}
//******************************************************************************
// Main ************************************************************************
// Send and receive three messages containing the example commands *************
//******************************************************************************
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
initClockTo16MHz();
initGPIO();
initSPI();
SLAVE_RST_OUT &= ~SLAVE_RST_PIN; // Now with SPI signals initialized,
__delay_cycles(100000);
SLAVE_RST_OUT |= SLAVE_RST_PIN; // reset slave
__delay_cycles(100000); // Wait for slave to initialize
COMMS_LED_OUT |= COMMS_LED_PIN;
__bis_SR_register(LPM0_bits + GIE); // CPU off, enable interrupts
SPI_Master_ReadReg(CMD_TYPE_2_SLAVE, TYPE_2_LENGTH);
CopyArray(ReceiveBuffer, SlaveType2, TYPE_2_LENGTH);
SPI_Master_ReadReg(CMD_TYPE_1_SLAVE, TYPE_1_LENGTH);
CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);
SPI_Master_ReadReg(CMD_TYPE_0_SLAVE, TYPE_0_LENGTH);
CopyArray(ReceiveBuffer, SlaveType0, TYPE_0_LENGTH);
SPI_Master_WriteReg(CMD_TYPE_2_MASTER, MasterType2, TYPE_2_LENGTH);
SPI_Master_WriteReg(CMD_TYPE_1_MASTER, MasterType1, TYPE_1_LENGTH);
SPI_Master_WriteReg(CMD_TYPE_0_MASTER, MasterType0, TYPE_0_LENGTH);
__bis_SR_register(LPM0_bits + GIE);
__no_operation();
return 0;
}
//******************************************************************************
// SPI Interrupt ***************************************************************
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
uint8_t ucb0_rx_val = 0;
switch(__even_in_range(UCB0IV, USCI_SPI_UCTXIFG))
{
case USCI_NONE: break;
case USCI_SPI_UCRXIFG:
ucb0_rx_val = UCB0RXBUF;
UCB0IFG &= ~UCRXIFG;
switch (MasterMode)
{
case TX_REG_ADDRESS_MODE:
if (RXByteCtr)
{
MasterMode = RX_DATA_MODE; // Need to start receiving now
//Send Dummy To Start
__delay_cycles(2000000);
SendUCB0Data(DUMMY);
}
else
{
MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer
//Send First
SendUCB0Data(TransmitBuffer[TransmitIndex++]);
TXByteCtr--;
}
break;
case TX_DATA_MODE:
if (TXByteCtr)
{
SendUCB0Data(TransmitBuffer[TransmitIndex++]);
TXByteCtr--;
}
else
{
//Done with transmission
MasterMode = IDLE_MODE;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
case RX_DATA_MODE:
if (RXByteCtr)
{
ReceiveBuffer[ReceiveIndex++] = ucb0_rx_val;
//Transmit a dummy
RXByteCtr--;
}
if (RXByteCtr == 0)
{
MasterMode = IDLE_MODE;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
else
{
SendUCB0Data(DUMMY);
}
break;
default:
__no_operation();
break;
}
__delay_cycles(1000);
break;
case USCI_SPI_UCTXIFG:
break;
default: break;
}
}
//******************************************************************************
// PORT1 Interrupt *************************************************************
// Interrupt occurs on button press and initiates the SPI data transfer ********
//******************************************************************************
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=BUTTON_VECTOR
__interrupt void Button_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(BUTTON_VECTOR))) Button_ISR (void)
#else
#error Compiler not supported!
#endif
{
BUTTON_LED_OUT |= BUTTON_LED_PIN;
BUTTON_IFG &= ~BUTTON_PIN; // button IFG cleared
BUTTON_IE &= ~BUTTON_PIN;
//Initiate
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}