1
\$\begingroup\$

I'm trying to write a communication protocol between an FPGA and a Microcontroller through an SPI, the μC being the Master here.

  • FPGA: Lattice iCE40 Ultra Breakout Board Rev.A (iCE5LP4K)
  • μC : Nordic nRF52 (PCA10040)

Here's the code I'm using for the FPGA part, simulation works nicely within Active HDL with process simulating the Master behavior. Here's how the transaction is supposed to look like (as explained in the link above):

  1. There is data available in tx_load_data registry --> trdy is high
  2. Master send command "0000 0000" instructing the slave to load the subsequent MOSI data into the receive register, while simultaneously outputting the transmit register to MISO (Master receives tx_load_data)
  3. trrdy goes low when the last bit is sent
  4. Likewise, rrdy goes high to assess that new data sent by the master has been received.

This works in simulation, I've managed to get the same as Figure 4 (see link above).

Trying to reproduce the same behavior with the μC attached, data is loaded, trrdy goes high, I send a command like "0x0A", it gets transmitted and there's something going on the MISO link, but I can't read it properly. From what I understood with SPI communications, I'm supposed to receive the response while I'm presenting data through MOSI. Is that right?

The following are samples of my C code, I'm pretty sure I'm doing something wrong but I lack experience. When debugging, the registers of the receive buffer are often filled with "111111" (words of 6 or 8 bits, it's inconsistent). The sendByte function is called within a button handler, and the rx buffer is printed out in the spi event handler, called at every transfer.

 /*
 * This function is supposed to ouput 00000000 01000001 to MOSI
 * Data received is buffered in m_rx_buf[20] array, declared in the header
 */
 void sendByteTest() {
 ret_code_t err_code;
 uint8_t m_tx[2];
 m_tx[0] = 0x0;
 m_tx[1] = 'A';
 m_length = sizeof(m_tx); /**< Transfer length. */
 err_code = nrf_drv_spi_transfer(&spi, m_tx, m_length, m_rx_buf, m_length);
 if (err_code != NRF_SUCCESS)
 NRF_LOG_PRINTF(" Error during transfer.\r\n");
 memset(m_rx_buf, 0, m_length);
}
int main(void) {
 /** CLOCK, BUTTONS, GPIOTE initialization omitted **/
 nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG(SPI_INSTANCE);
 spi_config.ss_pin = SPI_CS_PIN;
 spi_config.mode = NRF_DRV_SPI_MODE_2; // ss_n is active low, set accordingly
 spi_config.frequency = NRF_DRV_SPI_FREQ_125K;
 spi_config.bit_order = NRF_SPI_BIT_ORDER_MSB_FIRST;
 APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));
 int i = 0;
 while(1) {
 nrf_gpio_pin_toggle(LED_1);
 nrf_delay_ms(200);
 }
}
user2943160
2,9381 gold badge19 silver badges33 bronze badges
asked Jun 14, 2016 at 13:11
\$\endgroup\$
6
  • \$\begingroup\$ Its unclear whether you realise that your SPI slave doesn't know in advance what the master is going to send it - so it can only tailor its response after it has received something. It can't go back in time to change what it has already sent. So, the master sends a command to the slave (while simultaneously the slave returns either "nothing" or some default data) and then the master sends some dummy data to the slave in order to be able to read the slave's response to the previous command. \$\endgroup\$ Commented Jun 14, 2016 at 14:53
  • \$\begingroup\$ Ok, thank you for making this clearer. So I've been trying to do as you state, meaning that my first message is the command : 0x0, my trrdy bit goes high on the scope, so data is ready to be transmitted. (I bound those steps to buttons to ease up debug) Then I send uint8_t data[] = "A0円"; or sth like that, and I still don't fill my receive buffer... \$\endgroup\$ Commented Jun 14, 2016 at 15:06
  • \$\begingroup\$ Your master is in command of the SPI clock, and bits are only shifted in/out of SPI ports along with the SPI clock. So you have to send a byte in order to receive a byte. If you want to fill your receive buffer (20 bytes?) then your master has to send that many bytes to the slave. \$\endgroup\$ Commented Jun 14, 2016 at 15:16
  • \$\begingroup\$ Alright, that helped me a lot, thank you very much! The size were wrong indeed. I have a response in my buffer now (not yet at the right place? I'll look this up) I think I'm very close to figure this out, do you have an idea on how I should write the bit of code that assure me 0b00000000 command is being sent? data[] = {0}; makes the transfer hang (I'm using it in blocking mode for now) \$\endgroup\$ Commented Jun 14, 2016 at 15:48
  • \$\begingroup\$ data[] = "0A" kind of works to do the whole thing in one request, but I get the response in rx_buf[1], while rx_buf[0]='0円' this is why I couldn't see it before. But most importantly, it doesn't clear out the trdy bit, meaning that the Slave doesn't acknowledge the end of the transfer :( \$\endgroup\$ Commented Jun 14, 2016 at 16:09

1 Answer 1

1
\$\begingroup\$

The thing I didn't have in mind, is that SPI communications suggests that you should send as much data as you want to receive, not more, not less. So my buffer was noisy because of that. By setting m_length to 1 : err_code = nrf_drv_spi_transfer(&spi, m_tx, m_length, m_rx_buf, m_length); I am successfully transmitting one byte, while receiving exactly one byte in my receive buffer m_rx_buf

For the first transfer (command) I'm receiving dummy data that I don't process, for the actual transfer I'm buffering it and processing it.

answered Jun 16, 2016 at 8:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.