- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Greetings,
I was getting familiar with the SPI Master interrupts, so i started a project to send data via SPI taking advantage of the SPI TX FIFO and interrupts, so that way i don't stall the CPU waiting for the transfer to be completed, in the example the cpu triggers the SPI transfer and leave the interrupts to handle it, meanwhile the CPU toogles a digital output (silly but illustrate the point ;P), this can be useful when using PSoCs with no DMA.
To send just 3 bytes (less than the FIFO depth) using the spi_xfer_async function:
int main(void)
{
const uint8_t data_spi[10] = {0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A};
isr_SPI_Tx_StartEx(SPI_tx_handler);
// Enable interrupts
CyGlobalIntEnable;
// Configure and enable the peripherals
SPI_Start();
UART_Start();
UART_PutChar(0x0C); // clear the screen
UART_PutString("Test SPI with interrupts.\r\n");
while (1) {
if (TX_IDLE == tx_state) {
spi_xfer_asynch(data_spi, 3);
}
CyDelayUs(10);
LED_Write(~LED_Read());
}
}
The data transfer captured with a LA (you can see the LED toogling on the top trace):
To send just 10 bytes (more than the FIFO depth):
int main(void)
{
const uint8_t data_spi[10] = {0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A};
isr_SPI_Tx_StartEx(SPI_tx_handler);
// Enable interrupts
CyGlobalIntEnable;
// Configure and enable the peripherals
SPI_Start();
UART_Start();
UART_PutChar(0x0C); // clear the screen
UART_PutString("Test SPI with interrupts.\r\n");
while (1) {
if (TX_IDLE == tx_state) {
spi_xfer_asynch(data_spi, 10);
}
CyDelayUs(10);
LED_Write(~LED_Read());
}
}
The data transfer captured with a LA (you can see the LED toogling on the top trace):
Hope is useful to you (find the project attached, it use SPI based on UDB, but the principle apply to SCB as well), if you see something wrong let me know.
Regards,
Carlos
Solved! Go to Solution.
- Labels:
-
PSoC 5LP
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I worked a bit more and updated the buffer_t struct, now it just have a pointer to a uint8_t instead of the array of uint8_t, so now we must have an array of uint8_t with global scope to work with it, this avoid using memcpy (on the spi_xfer_async function) from the previous implementation.
This is the new main.c file
#include "project.h"
enum {
MAX_ITEMS = 10,
};
typedef enum {
TX_IDLE,
TX_TRANSFERING,
} tx_state_tag;
volatile tx_state_tag tx_state = TX_IDLE;
typedef struct {
uint8_t *const buffer;
uint8_t cnt;
uint8_t left_to_xfer;
} buffer_t;
uint8_t data_spi[MAX_ITEMS] = {0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A};
buffer_t tx_buffer = {
.buffer = data_spi,
.cnt = 0,
.left_to_xfer = 0,
};
void spi_xfer_async(uint8_t *data, const size_t size);
void SPI_handler(void);
int main(void)
{
isr_SPI_StartEx(SPI_handler);
CyGlobalIntEnable;
SPI_Start();
UART_Start();
UART_PutChar(0x0C); // clear the screen
UART_PutString("Test SPI with interrupts.\r\n");
while (1) {
if (TX_IDLE == tx_state) {
spi_xfer_async(tx_buffer.buffer, 3);
}
CyDelayUs(50);
LED_Write(~LED_Read());
if (TX_IDLE == tx_state) {
spi_xfer_async(tx_buffer.buffer, 10);
}
CyDelayUs(100);
LED_Write(~LED_Read());
}
}
The spi_xfer_async function:
void spi_xfer_async(uint8_t *data, const size_t size)
{
if (NULL != data) {
CyGlobalIntDisable;
if (TX_IDLE == tx_state) {
tx_state = TX_TRANSFERING;
if (size <= SPI_FIFO_SIZE) {
// fill the spi tx fifo
for (uint8_t i = 0; i < size; i++) {
SPI_WriteTxData(data);
}
} else {
tx_buffer.cnt = 2;
tx_buffer.left_to_xfer = size;
// put at least 2 bytes into the spi tx fifo
for (uint8_t i = 0; i < 2; i++) {
SPI_WriteTxData(data);
}
}
}
CyGlobalIntEnable;
}
}
The interrupt handler:
void SPI_handler(void)
{
// clear interrupt flag
volatile uint8_t sts = SPI_ReadTxStatus();
// TODO: Get the data from MISO
(void)SPI_ReadRxStatus();
if (TX_IDLE != tx_state) {
if (SPI_STS_BYTE_COMPLETE & sts) {
// do we still have data to send?
if (tx_buffer.left_to_xfer > tx_buffer.cnt) {
SPI_WriteTxData(tx_buffer.buffer[tx_buffer.cnt]);
tx_buffer.cnt++;
}
}
// the interrupt was triggered by the SPI_DONE flag
if (SPI_STS_SPI_IDLE & sts) {
tx_state = TX_IDLE;
}
}
}
We should be careful when updating the global data_spi array doing it when a transfer is not in process.
The project is attached (PSoC Creator 4.1).
Regards,
Carlos