Hi,
I am using the SPI Master 1 to control an EEPROM. I used the spi_example project to help get the code working. It all works fine if the code that initiates the SPI transfer is in main() or simply in a function called by main(). But if I attempt an SPI transfer in an "application timer" timeout handler function, it doesn't seem to work properly. It just seems like the transfer never completes. As shown in the oscilloscope trace below, the Chip Select (top yellow waveform) goes low fine, the SPI clock (green waveform) is generated fine, the data to the slave (blue waveform) is fine (the value is 00000110). Ignore the pink waveform. But for some reason the Chip Select doesn't go high, when it does if the SPI initiation is in main().
So when I next try to start a transfer I am stuck at:
while (!m_transfer_completed) { //wait for current transfer to complete }
Is there any reason why it would work in main but not in an application timer timeout handler?
Kind regards
Jack
edit:
I am setting the Chip Select high at the end of the transaction, where m_transfer_completed is also set as true. Then when I try to initiate another spi transfer, the code gets to the while loop. So essentially, the Chip Select pin should go high before the while loop occurs.
Here is some extracts from my code:
In the function timers_init() that is called in main, I have:
err_code = app_timer_create(&m_del_timer_id,
APP_TIMER_MODE_REPEATED,
del_timer_handler);
Here is the implementation of del_timer_handler
void del_timer_handler(void * p_context) { eeprom_write(m_tx_eeprom,m_rx_eeprom,m_eeprom_last_write_addr,m_eeprom_last_write_addr + EEPROM_PAGE_SIZE);
}
eeprom_write is defined as:
//To write to EEPROM, first send a write enable
static void eeprom_write(uint8_t * const tx_buffer, uint8_t * const rx_buffer, uint32_t from_addr, uint32_t to_addr) {
execute_eeprom_command(EEPROM_WREN,tx_buffer,rx_buffer,NULL,NULL); execute_eeprom_command(EEPROM_WRITE,tx_buffer,rx_buffer,from_addr,to_addr);
}
execute_eeprom_command is defined below:
void execute_eeprom_command(eeprom_command_t command, uint8_t * const tx_buffer, uint8_t * const rx_buffer, uint32_t from_addr, uint32_t to_addr)
{
uint16_t rx_len = 0;
uint16_t tx_len = 0;
while (!m_eeprom_transfer_completed)
{
//wait for current transfer to complete
}
m_eeprom_transfer_completed = false;
//Initalize buffers.
eeprom_buf_init(command,tx_buffer, &tx_len, rx_buffer, &rx_len, from_addr, to_addr);
//initialise SPI Master
spi1_master_init();
//Start transfer.
uint32_t err_code = spi_master_send_recv(SPI_MASTER_1, tx_buffer, tx_len, rx_buffer, rx_len);
APP_ERROR_CHECK(err_code);
}
Note, I am using the SS pin of the spi_master for the Chip Select. So the spi_master should automatically toggle the pin as required. I have also tried implementing the Chip Select independently of the spi_master and I still have the same problem. When doing this, I set the Chip Select to high in the spi master event handler:
void spi_master_1_event_handler(spi_master_evt_t spi_master_evt) {
switch (spi_master_evt.evt_type)
{
case SPI_MASTER_EVT_TRANSFER_COMPLETED:
//Check if received data is correct.
//Close SPI master.
spi_master_close(SPI_MASTER_1);
m_eeprom_transfer_completed = true;
// nrf_gpio_pin_set(EEPROM_CS_PIN);
break;
default:
//No implementation needed.
break;
}
}