Tool/software:
Hi Forum,
I have two launch pads configured to run at 24Mhz connected via SPIsending a random 32 Byte packet from the master to the slave using half duplex transmit polling method, I think the code is falling victim to the USCI42 errata but not sure. I have tried a bunch of different ways to resolve it with no luck.
The master is configured as follows
#include "spi_master_config.h"
#include "common.h"
#include "intrinsics.h"
#include "utils.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
// Defines
void spi_master_Init() {
P1SEL0 |= BIT1 | BIT2 | BIT3; // set 4-SPI pin as second function
//Set P6.3 and P6.6 to output direction
P6DIR |= BIT6;
P6OUT |= BIT6;
// For this example, CS is assumed to be on P3.1.
P3DIR |= BIT1; // Set P3.1 as output
P3OUT |= BIT1; // Deassert CS (active low)
// Disable the GPIO power-on default high-impedance mode to activate
// previously configured port settings.
PM5CTL0 &= ~LOCKLPM5;
UCB0CTLW0 |= UCSWRST; // **Put state machine in reset**
// 4-pin, 8-bit SPI master
UCB0CTLW0 |= UCMST | UCSYNC | UCCKPL;
// Clock polarity high, LSB
UCB0CTLW0 |= UCSSEL__SMCLK; // Use SMCLK as clock source
UCB0BR0 = 0x0C; // Divide SMCLK by 24 1MBits
UCB0BR1 = 0;
UCB0CTLW0 &= ~UCSWRST; // **Initialize USCI state machine**
}
uint8_t spi_master_Transfer(uint8_t *txbuff, uint8_t length)
{
int i = 0;
// Assert CS
P3OUT &= ~BIT1;
__delay_cycles(50);
for (i = 0; i < length; i++) {
while (!(UCB0IFG & UCTXIFG)); // Wait until TX buffer is ready
UCB0TXBUF = txbuff[i]; // Transmit data
// (Optional) If you want to flush the RX buffer:
while (!(UCB0IFG & UCRXIFG));
volatile uint8_t dummy = UCB0RXBUF;
}
// Wait until the SPI peripheral is no longer busy
while (UCB0STAT & UCBUSY);
__delay_cycles(50);
// Deassert CS
P3OUT |= BIT1;
return i;
}
uint8_t spi_master_Receive(uint8_t *rxbuff, uint8_t length)
{
int i = 0;
// Assert CS
P3OUT &= ~BIT1;
__delay_cycles(50);
// Ensure SPI is idle before starting
while (UCB0STAT & UCBUSY);
for (i = 0; i < length; i++)
{
// Wait until the TX buffer is ready
while (!(UCB0IFG & UCTXIFG));
// Transmit a dummy byte to generate clock for receiving data.
UCB0TXBUF = 0xFF;
// Wait until a byte has been received.
while (!(UCB0IFG & UCRXIFG));
// Store the received byte into the buffer.
rxbuff[i] = UCB0RXBUF;
}
// Wait until the SPI module is no longer busy (flush TX shift register)
while (UCB0STAT & UCBUSY);
__delay_cycles(50); // Allow for a clean CS transition
// Deassert CS
P3OUT |= BIT1;
return i; // Return the number of bytes received
}
The Transmit and receive is like this:
memset((void *)txbuff, 0, PACKET_BUFFER_MAX_SIZE);
memset((void *)rxbuff, 0, PACKET_BUFFER_MAX_SIZE);
randomizeData((void *)txbuff, PACKET_BUFFER_MAX_SIZE);
spi_master_Transfer((void *)txbuff, PACKET_BUFFER_MAX_SIZE);
__delay_cycles(120000);
spi_master_Receive((void *)rxbuff, PACKET_BUFFER_MAX_SIZE);
printf("\r\nTX Buffer:\r\n");
printBuffer((void *)txbuff, PACKET_BUFFER_MAX_SIZE);
printf("\r\nRX Buffer:\r\n");
printBuffer((void *)rxbuff, PACKET_BUFFER_MAX_SIZE);
send_receive_slave = false;
The SPI receive on the other board is setup using interrupts like this:
/* spi_slave.c
*
* Created on: Dec 3, 2023
* Author: gvigelet
*/
#include "common.h"
#include "sys/cdefs.h"
#include "spi_slave_config.h"
#include <stdio.h>
#include <string.h>
volatile uint8_t spiBuffer[PACKET_BUFFER_MAX_SIZE];
volatile unsigned int pSpiSend;
void spi_slave_Init()
{
P1SEL0 |= BIT4 | BIT5 | BIT6 | BIT7; // set 4-SPI pin as second function
UCA0CTLW0 |= UCSWRST; // **Put state machine in reset**
// 4-pin, 8-bit SPI slave
UCA0CTLW0 |= UCSYNC | UCCKPL | UCSTEM; // Synchronous mode, CPOL=1, CPHA=0
// Clock polarity high, MSB
UCA0CTLW0 |= UCSSEL__SMCLK; // Use SMCLK as clock source
UCA0CTLW0 &= ~UCMST; // Set as SPI slave
PM5CTL0 &= ~LOCKLPM5; // Disable the GPIO power-on default high-impedance mode
// to activate previously configured port settings
UCA0TXBUF = 0x00; // set to ready (use start packet byte)
pSpiSend = 0;
memset((void *)spiBuffer, 0, PACKET_BUFFER_MAX_SIZE);
UCA0CTLW0 &= ~UCSWRST; // **Initialize USCI state machine**
UCA0IE |= UCRXIE; // Enable USCI_A0 RX interrupt
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A0_VECTOR
__interrupt void USCI_A0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_A0_VECTOR))) USCI_A0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch (__even_in_range(UCA0IV, 4))
{
case USCI_NONE:
break; // No interrupt
case USCI_SPI_UCRXIFG:
spiBuffer[pSpiSend++] = UCA0RXBUF;
if (pSpiSend >= PACKET_BUFFER_MAX_SIZE) {
UCA0IE &= ~UCRXIE; // Disable further RX interrupts.
// Fill in temperature data into the last two bytes.
//spiBuffer[PACKET_BUFFER_MAX_SIZE-2] = (uint8_t)(rawTemp >> 8); // High byte
//spiBuffer[PACKET_BUFFER_MAX_SIZE-1] = (uint8_t)(rawTemp & 0xFF); // Low byte
pSpiSend = 0;
UCA0IE |= UCTXIE; // Enable TX interrupt for transmission.
}
break;
case USCI_SPI_UCTXIFG:
if (pSpiSend < PACKET_BUFFER_MAX_SIZE) {
UCA0TXBUF = spiBuffer[pSpiSend++];
} else {
UCA0IE &= ~UCTXIE; // Disable TX interrupts.
memset((void *)spiBuffer, 0, PACKET_BUFFER_MAX_SIZE);
pSpiSend = 0;
// Preload TXBUF with a default value for the next transaction.
UCA0TXBUF = 0x00; // Set this to whatever default is appropriate.
UCA0IE |= UCRXIE; // Re-enable RX interrupts for the next packet.
}
break;
default:
break;
}
}
The first transfer works correctly then all subsequent transfers error with an erroneous first byte as shown in the image below, I have the push button initiating the transfer.

After the first transfer the UCB0TXBUF has 0xFF in there and the next transfer gets that as the first byte. I haven't found a way to clear it, before the next transfer, resetting the peripheral didn't clear it? Is there a way to work around this issue or am I doing something incorrectly prior to subsequent transmissions? Any help would be greatly appreciated.
--- George