/** * @file ht_spi.c * @brief SPI Communication Function Source File * @date 07.May.2014 * @author hwangroy * @version 00.0.01 * * (c) Hunter Technology R&D Center. * * This file contains: * - function * . * SPI Comunication. * * Configure driver code generation: * @ Driver Enabable * - Enable SPI1 driver * * @ SPI1->SPI1 Data Formats Config * - Data Format0 Baudrate : 4500.000 * - Charlen : 8 * * @ SPI1->SPI1 Delays Config * - Chip Select Active to Transmit Start : 6(100.000ms) * - Transmit End to Chip Select Inavtive : 1(25.000ms) * * @ PINMUX->Pin Muxing * - MIBSPI1 Enable * - MIBSPI1SOMI_1, MIBSPI1SIMO_1 Diable * - MIBSPI1NCS_4, MIBSPI1NCS_5 Diable * * @ VIM * - MIBSPI1 high Enable * * @ Code Generate code click */ #include "FreeRTOS.h" #include "os_task.h" #include "os_semphr.h" #include "ht_spi.h" typedef struct { xSemaphoreHandle xSema; portTickType timeout; } g_spiState; static g_spiState Spi_State[5U]; static xSemaphoreHandle xSema; extern g_spiPacket g_spiPacket_t[5U]; extern void spiNotification(spiBASE_t *spi, uint32 flags); /** * @fn sint32 HTT_InitSPI4(void) * @brief Initializes SPI4 Driver * @param[in] N/A: * @return N/A: * @remarks This function initializes at SPI Communication. */ sint32 HTT_InitSPI4(void) { sint32 init_spi4_ret = 0; /** @b initialize @b SPI4 */ /** bring SPI out of reset */ spiREG4->GCR0 = 0U; spiREG4->GCR0 = 1U; /** SPI4 master mode and clock configuration */ spiREG4->GCR1 = (spiREG4->GCR1 & 0xFFFFFFFCU) | ((uint32)((uint32)1U << 1U) /* CLOKMOD */ | 1U); /* MASTER */ // spiREG4->GCR1 |= (uint32)((uint32)1U << 16U); /* Internal Loop-Back Test */ /** SPI4 enable pin configuration */ spiREG4->INT0 = (spiREG4->INT0 & 0xFEFFFFFFU) | (uint32)((uint32)0U << 24U); /* ENABLE HIGHZ */ /** - Delays */ spiREG4->DELAY = (uint32)((uint32)8U << 24U) /* C2TDELAY */ | (uint32)((uint32)3U << 16U) /* T2CDELAY */ | (uint32)((uint32)0U << 8U) /* T2EDELAY */ | (uint32)((uint32)0U << 0U); /* C2EDELAY */ /** - Data Format 0 */ spiREG4->FMT0 = (uint32)((uint32)0U << 24U) /* wdelay */ | (uint32)((uint32)0U << 23U) /* parity Polarity */ | (uint32)((uint32)0U << 22U) /* parity enable */ | (uint32)((uint32)0U << 21U) /* wait on enable */ | (uint32)((uint32)0U << 20U) /* shift direction */ | (uint32)((uint32)0U << 17U) /* clock polarity */ | (uint32)((uint32)1U << 16U) /* clock phase */ | (uint32)((uint32)177U << 8U) /* baudrate prescale */ | (uint32)((uint32)8U << 0U); /* data word length */ /** - Data Format 1 */ spiREG4->FMT1 = (uint32)((uint32)0U << 24U) /* wdelay */ | (uint32)((uint32)0U << 23U) /* parity Polarity */ | (uint32)((uint32)0U << 22U) /* parity enable */ | (uint32)((uint32)0U << 21U) /* wait on enable */ | (uint32)((uint32)0U << 20U) /* shift direction */ | (uint32)((uint32)0U << 17U) /* clock polarity */ | (uint32)((uint32)0U << 16U) /* clock phase */ | (uint32)((uint32)79U << 8U) /* baudrate prescale */ | (uint32)((uint32)16U << 0U); /* data word length */ /** - Data Format 2 */ spiREG4->FMT2 = (uint32)((uint32)0U << 24U) /* wdelay */ | (uint32)((uint32)0U << 23U) /* parity Polarity */ | (uint32)((uint32)0U << 22U) /* parity enable */ | (uint32)((uint32)0U << 21U) /* wait on enable */ | (uint32)((uint32)0U << 20U) /* shift direction */ | (uint32)((uint32)0U << 17U) /* clock polarity */ | (uint32)((uint32)0U << 16U) /* clock phase */ | (uint32)((uint32)79U << 8U) /* baudrate prescale */ | (uint32)((uint32)16U << 0U); /* data word length */ /** - Data Format 3 */ spiREG4->FMT3 = (uint32)((uint32)0U << 24U) /* wdelay */ | (uint32)((uint32)0U << 23U) /* parity Polarity */ | (uint32)((uint32)0U << 22U) /* parity enable */ | (uint32)((uint32)0U << 21U) /* wait on enable */ | (uint32)((uint32)0U << 20U) /* shift direction */ | (uint32)((uint32)0U << 17U) /* clock polarity */ | (uint32)((uint32)0U << 16U) /* clock phase */ | (uint32)((uint32)79U << 8U) /* baudrate prescale */ | (uint32)((uint32)16U << 0U); /* data word length */ /** - set interrupt levels */ spiREG4->LVL = (uint32)((uint32)0U << 9U) /* TXINT */ | (uint32)((uint32)0U << 8U) /* RXINT */ | (uint32)((uint32)0U << 6U) /* OVRNINT */ | (uint32)((uint32)0U << 4U) /* BITERR */ | (uint32)((uint32)0U << 3U) /* DESYNC */ | (uint32)((uint32)0U << 2U) /* PARERR */ | (uint32)((uint32)0U << 1U) /* TIMEOUT */ | (uint32)((uint32)0U << 0U); /* DLENERR */ /** - clear any pending interrupts */ spiREG4->FLG |= 0xFFFFU; /** - enable interrupts */ spiREG4->INT0 = (spiREG4->INT0 & 0xFFFF0000U) | (uint32)((uint32)0U << 9U) /* TXINT */ | (uint32)((uint32)0U << 8U) /* RXINT */ | (uint32)((uint32)0U << 6U) /* OVRNINT */ | (uint32)((uint32)0U << 4U) /* BITERR */ | (uint32)((uint32)0U << 3U) /* DESYNC */ | (uint32)((uint32)0U << 2U) /* PARERR */ | (uint32)((uint32)0U << 1U) /* TIMEOUT */ | (uint32)((uint32)0U << 0U); /* DLENERR */ /** @b initialize @b SPI4 @b Port */ /** - SPI4 Port output values */ spiREG4->PC3 = (uint32)((uint32)1U << 0U) /* SCS[0] */ | (uint32)((uint32)0U << 8U) /* ENA */ | (uint32)((uint32)0U << 9U) /* CLK */ | (uint32)((uint32)0U << 10U) /* SIMO */ | (uint32)((uint32)0U << 11U); /* SOMI */ /** - SPI4 Port direction */ spiREG4->PC1 = (uint32)((uint32)1U << 0U) /* SCS[0] */ | (uint32)((uint32)0U << 8U) /* ENA */ | (uint32)((uint32)1U << 9U) /* CLK */ | (uint32)((uint32)1U << 10U) /* SIMO */ | (uint32)((uint32)0U << 11U); /* SOMI */ /** - SPI4 Port open drain enable */ spiREG4->PC6 = (uint32)((uint32)0U << 0U) /* SCS[0] */ | (uint32)((uint32)0U << 8U) /* ENA */ | (uint32)((uint32)0U << 9U) /* CLK */ | (uint32)((uint32)0U << 10U) /* SIMO */ | (uint32)((uint32)0U << 11U); /* SOMI */ /** - SPI4 Port pullup / pulldown selection */ spiREG4->PC8 = (uint32)((uint32)1U << 0U) /* SCS[0] */ | (uint32)((uint32)1U << 8U) /* ENA */ | (uint32)((uint32)1U << 9U) /* CLK */ | (uint32)((uint32)1U << 10U) /* SIMO */ | (uint32)((uint32)1U << 11U); /* SOMI */ /** - SPI4 Port pullup / pulldown enable*/ spiREG4->PC7 = (uint32)((uint32)0U << 0U) /* SCS[0] */ | (uint32)((uint32)0U << 8U) /* ENA */ | (uint32)((uint32)0U << 9U) /* CLK */ | (uint32)((uint32)0U << 10U) /* SIMO */ | (uint32)((uint32)0U << 11U); /* SOMI */ /* SPI4 set all pins to functional */ spiREG4->PC0 = (uint32)((uint32)1U << 0U) /* SCS[0] */ | (uint32)((uint32)1U << 8U) /* ENA */ | (uint32)((uint32)1U << 9U) /* CLK */ | (uint32)((uint32)1U << 10U) /* SIMO */ | (uint32)((uint32)1U << 11U); /* SOMI */ /** - Initialize TX and RX data buffer Status */ g_spiPacket_t[3U].tx_data_status = SPI_READY; g_spiPacket_t[3U].rx_data_status = SPI_READY; /** - Finally start SPI4 */ spiREG4->GCR1 = (spiREG4->GCR1 & 0xFEFFFFFFU) | 0x01000000U; vSemaphoreCreateBinary(xSema); Spi_State[3U].timeout = 100; if(xSema == NULL) { init_spi4_ret = -1; } return init_spi4_ret; } /** * @fn sint32 HTT_SendSPI(spiBASE_t *spi, uint8 ch, uint8 format, uint8 * srcbuff, uint32 blocksize) * @brief Send a SPI message * @param[in] spi : Node Point to SPI Node. * @param[in] ch : Slave Device Channel. * @param[in] format : Data Format Select. * @param[in] srcbuff : Data Pointer to SPI Send data. * @param[in] blocksize : Data size to SPI Send data. * @return The function will return: * - 0: The sends of the SPI driver the Send Data was successful. * - -1: The sends of the SPI driver the Send Data wasn't successful. * @remarks This function send to the slave device using SPI Communication. */ sint32 HTT_SendSPI(spiBASE_t *spi, uint8 ch, uint8 format, uint8 * srcbuff, uint32 blocksize) { sint32 send_spi_ret = 0; uint32 index = (spi == spiREG1) ? 0U :((spi==spiREG2) ? 1U : ((spi==spiREG3) ? 2U:((spi==spiREG4) ? 3U:4U))); uint8 sendch = (ch == 0U) ? (uint8)SPI_CS_0 :((ch == 1U) ? (uint8)SPI_CS_1 :((ch == 2U) ? (uint8)SPI_CS_2 :((ch == 3U) ? (uint8)SPI_CS_3: (uint8)0xFFU))); SPIDATAFMT_t sendformat = (format == 0U) ? (uint8)SPI_FMT_0 :((format == 1U) ? (uint8)SPI_FMT_1 :((format == 2U) ? (uint8)SPI_FMT_2 :((format == 3U) ? (uint8)SPI_FMT_3: (uint8)0xFFU))); spiDAT1_t dataconfig1_t; /* MibSpi Test Source */ dataconfig1_t.CS_HOLD = TRUE; dataconfig1_t.WDEL = TRUE; dataconfig1_t.DFSEL = sendformat; dataconfig1_t.CSNR = sendch; g_spiPacket_t[index].tx_length = blocksize; g_spiPacket_t[index].txdata_ptr = srcbuff; g_spiPacket_t[index].g_spiDataFormat = dataconfig1_t; g_spiPacket_t[index].tx_data_status = SPI_PENDING; spi->INT0 |= 0x0200U; while(g_spiPacket_t[index].tx_data_status == SPI_PENDING) { ; } return send_spi_ret; } /** * @fn sint32 HTT_ReceiveSPI(spiBASE_t *spi, uint8 ch, uint8 format, uint8 * destbuff, uint32 blocksize) * @brief Received a SPI message * @param[in] spi : Node Point to SPI Node. * @param[in] ch : Slave Device Channel. * @param[in] format : Data Format Select. * @param[in] srcbuff : Data Pointer to SPI Received data. * @param[in] blocksize : Data size to SPI Received data. * @return N/A: * @remarks This function receive from the slave device using SPI Communication. */ sint32 HTT_ReceiveSPI(spiBASE_t *spi, uint8 ch, uint8 format, uint8 * destbuff, uint32 blocksize) { sint32 receive_spi_ret = 0; uint32 index = (spi == spiREG1) ? 0U :((spi==spiREG2) ? 1U : ((spi==spiREG3) ? 2U:((spi==spiREG4) ? 3U:4U))); uint8 recech = (ch == 0U) ? (uint8)SPI_CS_0 :((ch == 1U) ? (uint8)SPI_CS_1 :((ch == 2U) ? (uint8)SPI_CS_2 :((ch == 3U) ? (uint8)SPI_CS_3: (uint8)0xFFU))); SPIDATAFMT_t receformat = (format == 0U) ? (uint8)SPI_FMT_0 :((format == 1U) ? (uint8)SPI_FMT_1 :((format == 2U) ? (uint8)SPI_FMT_2 :((format == 3U) ? (uint8)SPI_FMT_3: (uint8)0xFFU))); spiDAT1_t dataconfig1_t; /* MibSpi Test Source */ dataconfig1_t.CS_HOLD = TRUE; dataconfig1_t.WDEL = TRUE; dataconfig1_t.DFSEL = receformat; dataconfig1_t.CSNR = recech; g_spiPacket_t[index].rx_length = blocksize; g_spiPacket_t[index].rxdata_ptr = destbuff; g_spiPacket_t[index].g_spiDataFormat = dataconfig1_t; g_spiPacket_t[index].rx_data_status = SPI_PENDING; spi->INT0 |= 0x0100U; while(g_spiPacket_t[index].rx_data_status == SPI_PENDING) { ; } return receive_spi_ret; } /** * @fn sint32 HTT_SendAndReceiveSPI(spiBASE_t *spi, uint8 ch, uint8 format, uint8 * srcbuff, uint32 src_size, uint8 * destbuff, uint32 des_size) * @brief Send a Receive SPI message * @param[in] spi : Node Point to SPI Node. * @param[in] ch : Slave Device Channel. * @param[in] format : Data Format Select. * @param[in] srcbuff : Data Pointer to SPI Send data. * @param[in] src_size : Data size to SPI Send data. * @param[in] destbuff : Data Pointer to SPI Received data. * @param[in] des_size : Data size to SPI Received data. * @return N/A: * @remarks This function send and receive to the slave device using SPI Communication. */ sint32 HTT_SendAndReceiveSPI(spiBASE_t *spi, uint8 ch, uint8 format, uint8 * srcbuff, uint32 src_size, uint8 * destbuff, uint32 des_size) { sint32 sendandrec_spi_ret = 0; uint32 index = (spi == spiREG1) ? 0U :((spi==spiREG2) ? 1U : ((spi==spiREG3) ? 2U:((spi==spiREG4) ? 3U:4U))); uint8 sendandrecech = (ch == 0U) ? (uint8)SPI_CS_0 :((ch == 1U) ? (uint8)SPI_CS_1 :((ch == 2U) ? (uint8)SPI_CS_2 :((ch == 3U) ? (uint8)SPI_CS_3: (uint8)0xFFU))); SPIDATAFMT_t sendandrecefrormat = (format == 0U) ? (uint8)SPI_FMT_0 :((format == 1U) ? (uint8)SPI_FMT_1 :((format == 2U) ? (uint8)SPI_FMT_2 :((format == 3U) ? (uint8)SPI_FMT_3: (uint8)0xFFU))); spiDAT1_t dataconfig1_t; /* MibSpi Test Source */ dataconfig1_t.CS_HOLD = TRUE; dataconfig1_t.WDEL = TRUE; dataconfig1_t.DFSEL = sendandrecefrormat; dataconfig1_t.CSNR = sendandrecech; g_spiPacket_t[index].tx_length = src_size; g_spiPacket_t[index].rx_length = des_size; g_spiPacket_t[index].txdata_ptr = srcbuff; g_spiPacket_t[index].rxdata_ptr = destbuff; g_spiPacket_t[index].g_spiDataFormat = dataconfig1_t; g_spiPacket_t[index].tx_data_status = SPI_PENDING; g_spiPacket_t[index].rx_data_status = SPI_PENDING; spi->FLG = 0x00000000; spi->INT0 |= 0x0200U; while(g_spiPacket_t[index].tx_data_status == SPI_PENDING) { ; } spi->FLG = 0x00000000; spi->INT0 |= 0x0100U; if(xSemaphoreTake(xSema, (portTickType)100) == pdTRUE ) { while(g_spiPacket_t[index].rx_data_status == SPI_PENDING) { ; } } else { sendandrec_spi_ret = -1; } return sendandrec_spi_ret; } /** * @fn void spiNotification(spiBASE_t *spi, uint32 flags) * @brief Message notification * @param[in] spi : Node Pointer to spi node: * - spiREG1: SCI1 node pointer * - spiREG2: SCI2 node pointer * - spiREG3: SCI3 node pointer * - spiREG4: SCI4 node pointer * @param[in] flags : Interrupt number of SPI: * @return N/A: * @remarks This function is called when interrupt occurs. */ void spiNotification(spiBASE_t *spi, uint32 flags) { static signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; uint32 index = (spi == spiREG1) ? 0U :((spi==spiREG2) ? 1U : ((spi==spiREG3) ? 2U:((spi==spiREG4) ? 3U:4U))); uint32 vec = spi->INTVECT0; switch(vec) { case 0x24U: /* Receive Buffer Full Interrupt */ { uint8 *destbuff; destbuff = g_spiPacket_t[index].rxdata_ptr; *destbuff = (uint16)spi->BUF; spi->FLG = (spi->FLG & 0x0000FFFFU) & (~(uint32)0x0100U); /* Flag Clear */ /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */ g_spiPacket_t[index].rxdata_ptr++; g_spiPacket_t[index].rx_length--; if(g_spiPacket_t[index].rx_length == 0U) { spi->INT0 = (spi->INT0 & 0x0000FFFFU) & (~(uint32)0x0100U); g_spiPacket_t[index].rx_data_status = SPI_COMPLETED; xSemaphoreGiveFromISR(xSema, &xHigherPriorityTaskWoken); // xSemaphoreGive(xSema); spiEndNotification(spi); } break; } case 0x28U: /* Transmit Buffer Empty Interrupt */ { volatile uint32 SpiBuf; uint32 Chip_Select_Hold = 0U; uint32 WDelay = (g_spiPacket_t[index].g_spiDataFormat.WDEL) ? 0x04000000U: 0U; SPIDATAFMT_t DataFormat = g_spiPacket_t[index].g_spiDataFormat.DFSEL; uint8 ChipSelect = g_spiPacket_t[index].g_spiDataFormat.CSNR; uint8 Tx_Data = *g_spiPacket_t[index].txdata_ptr; g_spiPacket_t[index].tx_length--; if((g_spiPacket_t[index].tx_length == 0U) && (g_spiPacket_t[index].rx_length == 0U)) { Chip_Select_Hold = 0U; } else { Chip_Select_Hold = (g_spiPacket_t[index].g_spiDataFormat.CS_HOLD) ? 0x10000000U : 0U; } spi->DAT1 = ((uint32)DataFormat << 24U) | ((uint32)ChipSelect << 16U) | (WDelay) | (Chip_Select_Hold) | (uint32)Tx_Data; /*SAFETYMCUSW 567 S MR:17.1,17.4 <APPROVED> "Pointer increment needed" */ g_spiPacket_t[index].txdata_ptr++; /* Dummy Receive read if no RX Interrupt enabled */ if(((spi->INT0 & 0x0000FFFFU)& 0x0100U) == 0U) { while((spi->FLG & 0x00000100U) == 0x00000100U) { SpiBuf = spi->BUF; } } if(g_spiPacket_t[index].rx_length != 0U) { while((spi->FLG & 0x00000100U) == 0x00000100U) { SpiBuf = spi->BUF; } spi->FLG = (spi->FLG & 0x0000FFFFU) & (~(uint32)0x0100U); /* Flag Clear */ if(g_spiPacket_t[index].rx_length == 1U) { Chip_Select_Hold = 0U; } else { Chip_Select_Hold = (g_spiPacket_t[index].g_spiDataFormat.CS_HOLD) ? 0x10000000U : 0U; } spi->DAT1 = ((uint32)DataFormat << 24U) | ((uint32)ChipSelect << 16U) | (WDelay) | (Chip_Select_Hold) | (uint32)0xFF; } if(g_spiPacket_t[index].tx_length == 0U) { spi->INT0 = (spi->INT0 & 0x0000FFFFU) & (~(uint32)0x0200U); /* Disable Interrupt */ g_spiPacket_t[index].tx_data_status = SPI_COMPLETED; spiEndNotification(spi); } break; } default: /* Clear Flags and return */ spi->FLG = flags; spiNotification(spi, flags & 0xFFU); break; } }
I trying the FreeRTOS on TMS570LS3137. Create a project using the TMS570LS317ZWT_FREERTOS template in the HalCoGen(3.9.0).
I add the timeout of receive function at SPI Driver,
a. wait 100ms timeout using xSemaphoreTake() into HTT_ReceiveSPI().
b. use xSemaphoreGiveFromISR() into rx interruppt of spiNotification().
If normal, The vSemaphoreTask() is obtain semaphore through xSemaphoreGiveFromISR() at SPINotification(). so, it is not problem of operate.
If doesn't received the data, doesn't occur the interrupt. so, The vSemaphoreTask() isn't obtain semaphore through xSemaphoreGiveFromISR() at SPINotification . vSemaphoreTask() have to return the pdFALSE, after 100ms. but, continuously wait at vSemaphoreTask().
sint32 HTT_SendAndReceiveSPI() {
.....
if(xSemaphoreTake(xSema, (portTickType)100) == pdTRUE ) {
while(g_spiPacket_t[index].rx_data_status == SPI_PENDING) {
;
}
else {
sendandrec_spi_ret = -1;
}
}
void spiNotification() {
switch(vec) case 0x24U:
...
if(g_spiPacket_t[index].rx_length == 0U) {
spi->INT0 = (spi->INT0 & 0x0000FFFFU) & (~(uint32)0x0100U);
g_spiPacket_t[index].rx_data_status = SPI_COMPLETED;
xSemaphoreGiveFromISR(xSema, &xHigherPriorityTaskWoken);
spiEndNotification(spi);
}
break;
}