SPI Slave Driver
Re: SPI Slave Driver
I'd like to bump this thread as I need to do the same thing.
I have implemented plyatov's method of adding a switch in the spiConfig to bypass the hard coded MSTR setting on the SPI_CR1.
I'm not sure which chibi spi methods I should call to handle a transaction of data from the salve to the master.
I use the following in one of my drivers that is in master mode:
spiAcquireBus(spip); // Acquire ownership of the bus.
spiSelect(spip); // Slave Select assertion.
spiSend(spip, headerLength, headerBuffer); // Slave Register Select
spiSend(spip, bodylength, bodyBuffer); // Write operation.
spiUnselect(spip); // Slave Select de-assertion.
spiReleaseBus(spip); // Ownership release.
Though that is not working here.
Should I be using spiStartExchange? Is spiAcquireBus and spiSelect not necessary?
I am just randomly trying methods, it isn't working well. Does anyone know the proper sequence of calls for slave mode transmit?
I basically need something that is going to take a buffer of data, and then wait until the master begins to clock it through and return when complete.
Cheers
Alex
I have implemented plyatov's method of adding a switch in the spiConfig to bypass the hard coded MSTR setting on the SPI_CR1.
I'm not sure which chibi spi methods I should call to handle a transaction of data from the salve to the master.
I use the following in one of my drivers that is in master mode:
spiAcquireBus(spip); // Acquire ownership of the bus.
spiSelect(spip); // Slave Select assertion.
spiSend(spip, headerLength, headerBuffer); // Slave Register Select
spiSend(spip, bodylength, bodyBuffer); // Write operation.
spiUnselect(spip); // Slave Select de-assertion.
spiReleaseBus(spip); // Ownership release.
Though that is not working here.
Should I be using spiStartExchange? Is spiAcquireBus and spiSelect not necessary?
I am just randomly trying methods, it isn't working well. Does anyone know the proper sequence of calls for slave mode transmit?
I basically need something that is going to take a buffer of data, and then wait until the master begins to clock it through and return when complete.
Cheers
Alex
Re: SPI Slave Driver
Xela wrote:I'm not sure which chibi spi methods I should call to handle a transaction of data from the salve to the master.
Here is example of how to use my SPI slave patch in ChibiOS applications.
Example communicates with SPI master by means of tl_start_receive() and tl_start_send().
Additionally, assert_dsp_rdy() and clear_dsp_rdy() used for indication of SPI slave readiness to communicate with SPI master. Falling edge of dsp_rdy line generates IRQ for master and it initiates SPI transfer.
Code: Select all
static const SPIConfig spi2_cfg = {
.slave_mode = true,
.end_cb = NULL,
.ssport = GPIOB,
.sspad = GPIOB_SPI2_NSS,
.cr1 = 0 // SPI_MODE_0.
};
#if (SPI_USE_WAIT != TRUE)
#error enable SPI_USE_WAIT in the halconf.h
#endif // SPI_USE_WAIT
/**
* @brief Sends data over the SPI bus.
* @details This synchronous function performs a transmit operation.
* @pre In order to use this function the option @p SPI_USE_WAIT must be
* enabled.
* @pre In order to use this function the driver must have been configured
* without callbacks (@p end_cb = @p NULL).
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to send
* @param[in] txbuf the pointer to the transmit buffer
*
* @api
*/
static void sspiSend(SPIDriver *spip, size_t n, const void *txbuf) {
osalDbgCheck((spip != NULL) && (n > 0U) && (txbuf != NULL));
osalSysLock();
osalDbgAssert(spip->state == SPI_READY, "not ready");
osalDbgAssert(spip->config->end_cb == NULL, "has callback");
spiStartSendI(spip, n, txbuf);
assert_dsp_rdy();
(void) osalThreadSuspendS(&spip->thread);
clear_dsp_rdy();
osalSysUnlock();
}
/**
* @brief Receives data from the SPI bus.
* @details This synchronous function performs a receive operation.
* @pre In order to use this function the option @p SPI_USE_WAIT must be
* enabled.
* @pre In order to use this function the driver must have been configured
* without callbacks (@p end_cb = @p NULL).
* @note The buffers are organized as uint8_t arrays for data sizes below
* or equal to 8 bits else it is organized as uint16_t arrays.
*
* @param[in] spip pointer to the @p SPIDriver object
* @param[in] n number of words to receive
* @param[out] rxbuf the pointer to the receive buffer
*
* @api
*/
static void sspiReceive(SPIDriver *spip, size_t n, void *rxbuf) {
osalDbgCheck((spip != NULL) && (n > 0U) && (rxbuf != NULL));
osalSysLock();
osalDbgAssert(spip->state == SPI_READY, "not ready");
osalDbgAssert(spip->config->end_cb == NULL, "has callback");
spiStartReceiveI(spip, n, rxbuf);
assert_dsp_rdy();
(void) osalThreadSuspendS(&spip->thread);
clear_dsp_rdy();
osalSysUnlock();
}
/**
* tl_start_receive - setup SPI for data reception.
*/
static void tl_start_receive(void)
{
tl_state = receive_packet;
spiStart(&SPID2, &spi2_cfg);
sspiReceive(&SPID2, TL_PACKET_SIZE, tl_buf);
}
/**
* tl_start_send - setup SPI for data transmission.
*/
static void tl_start_send(void)
{
tl_state = send_packet;
spiStart(&SPID2, &spi2_cfg);
sspiSend(&SPID2, TL_PACKET_SIZE, tl_buf);
}
Re: SPI Slave Driver
Now that I have my master side built up, I don't quite have this working yet.
It is likely a configuration issue though I am not 100% certain I understand the behavior of this function in terms of execution and program flow.
This spiStartSendI() will send a byte to the SPI buffer via DMA.
The loading of the SPI data register will be handled by the SPI peripheral on board the STM MCU.
I don't have to worry about the fine low level details of signalling.
I am not entirely confident if i should treat spiStartSendI() as a blocking or non-blocking function.
Will this thread remain suspended until the tx buffer has been read?
I am unfortunately working with hardware that does not have an auxiliary line to use as a DATA_RDY signal (will add one later).
At this point i just need to transmit one byte to confirm the connection works.
I run my slave board code and I assume it loads the SPI data register (LEDs/step through show the function just then waits)
On the master side i then manually execute a transfer (with code that works ok in loopback).
While I triple check every single config detail and brute force different baud rates, could someone confirm I do understand how this function is meant to be used?
Alex
It is likely a configuration issue though I am not 100% certain I understand the behavior of this function in terms of execution and program flow.
This spiStartSendI() will send a byte to the SPI buffer via DMA.
The loading of the SPI data register will be handled by the SPI peripheral on board the STM MCU.
I don't have to worry about the fine low level details of signalling.
I am not entirely confident if i should treat spiStartSendI() as a blocking or non-blocking function.
Will this thread remain suspended until the tx buffer has been read?
I am unfortunately working with hardware that does not have an auxiliary line to use as a DATA_RDY signal (will add one later).
At this point i just need to transmit one byte to confirm the connection works.
I run my slave board code and I assume it loads the SPI data register (LEDs/step through show the function just then waits)
On the master side i then manually execute a transfer (with code that works ok in loopback).
While I triple check every single config detail and brute force different baud rates, could someone confirm I do understand how this function is meant to be used?
Alex
Re: SPI Slave Driver
Xela wrote:It is likely a configuration issue
You should use only SPIx_NSS line as Chip Select. And it must be configured into Alternate mode to behave as NSS pin of corresponding SPI module.
Typically this is made in the board.h file.
Xela wrote:This spiStartSendI() will send a byte to the SPI buffer via DMA.
It will not send. It will only prepare SPI module for DMA tranfer. The transfer will be started by means of HW, only when SPI master assert NSS line of MCU.
Xela wrote:I am not entirely confident if i should treat spiStartSendI() as a blocking or non-blocking function.
It is non blocking and exits nearly immediately after call.
Xela wrote:Will this thread remain suspended until the tx buffer has been read?
Thread will be suspended by osalThreadSuspendS() until SPI transfer is finalized (NSS line is cleared).
It will be quite helpfull if you will use logical analyzer to see SPI diagrams. I recommend "Saleae Logic 16". The "Saleae Logic 8" can be used too, but it is quite limited. Look at saleae.com or better at aliexpress.com for cheaper clones

Return to “Small Change Requests”
Who is online
Users browsing this forum: No registered users and 1 guest