This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

SPI Master transfer not completing

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().

image description

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;
}

}

Parents
  • Hi Jack

    I believe that John's comments are valid, that your while loop in the app_timer interrupt handler is blocking the SPI interrupt which has the same priority. Are you still having problems? You could do as John has suggested and set a flag in the app_timer interrupt handler and then check for that flag in main, or you could use the scheduler as documented here, which basically does the same thing. Simply call app_sched_event_put() from your app_timer interrupt handler and then add the scheduler handler in main and the app_sched_execute() in the main loop in order to execute the scheduler handler.

    I then suggest you press the "convert to answer" for the comment that you think is the most adequate answer to your question. Then accept that answer by clicking the "accept" icon below the voting arrows.

Reply
  • Hi Jack

    I believe that John's comments are valid, that your while loop in the app_timer interrupt handler is blocking the SPI interrupt which has the same priority. Are you still having problems? You could do as John has suggested and set a flag in the app_timer interrupt handler and then check for that flag in main, or you could use the scheduler as documented here, which basically does the same thing. Simply call app_sched_event_put() from your app_timer interrupt handler and then add the scheduler handler in main and the app_sched_execute() in the main loop in order to execute the scheduler handler.

    I then suggest you press the "convert to answer" for the comment that you think is the most adequate answer to your question. Then accept that answer by clicking the "accept" icon below the voting arrows.

Children
No Data
Related