SPI interface freezes within the DMA ISR - [SOLVED] -

External hardware connected to the STM32 board
stevestrong
Posts: 2048
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

SPI interface freezes within the DMA ISR - [SOLVED] -

Post by stevestrong » Wed Dec 28, 2016 11:08 pm

I am posting here as a side-issue of this post.

The setup:
SPI is driven by the DMA. DMA provides 16 bit data stream from a memory array to SPI which just outputs serial data on the MOSI pin.
The DMA is configured to generate an interrupt after it finished to send all the data to SPI.

The flow:
The DMA IRQ is correctly generated after data transmission finished, but before all 16 bits are pulsed out by SPI.
That's why it is needed to check the SPI status before sending new data.

The problem:
In the DMA ISR, checking the TXE and BSY flags of the SPI interface using this code doesn't wok:

Code: Select all

	while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
/* and */
	while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." 
the while loops are infinitely executed, although I can see with the scope that no more extra data is being output on MOSI pin.

I cannot disable/reset the SPI interface as long as data bits are being output, but I am unable to check when is finished, so it's kind of doom-loop.

What am I doing wrong?
And which options do I have except resetting the SPI forcedly after a predetermined delay?
Last edited by stevestrong on Thu Dec 29, 2016 9:01 pm, edited 4 times in total.

User avatar
ahull
Posts: 1718
Joined: Mon Apr 27, 2015 11:04 pm
Location: Sunny Scotland
Contact:

Re: SPI interface freezes within the DMA ISR

Post by ahull » Thu Dec 29, 2016 12:47 am

Bear with me as I am simply looking at the documentation, and have no idea (as usual) what I am talking about... but...
I can't see anything obviously wrong with your code (so you may have encountered a bug)... but is true=1 is false=0 what exactly does spi_is_busy return?! Are we being fooled by comparing a boolean with an int or something daft?

uint8 spi_is_busy(spi_dev * dev)
Determine whether the device’s peripheral busy (SPI_SR_BSY) flag is set.
Parameters:
dev -
SPI device
Return:
true, iff dev’s BSY flag is set.


... appears to be a valid way to see if you are ready to fire off the next transmission. At least that is how I am reading http://docs.leaflabs.com/static.leaflab ... i/spi.html
I am probably barking up the wrong tree (or perhaps not even barking in the right forest). :D
- Andy Hull -

stevestrong
Posts: 2048
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: SPI interface freezes within the DMA ISR

Post by stevestrong » Thu Dec 29, 2016 7:37 am

Thanks, Andy, but this was copied from a working part of code.
I also tried your suggestion, but as expected, same "bug", it is something else there.

Btw, same code snippet works flawlessly if is executed on the main level, not within the ISR.

User avatar
ahull
Posts: 1718
Joined: Mon Apr 27, 2015 11:04 pm
Location: Sunny Scotland
Contact:

Re: SPI interface freezes within the DMA ISR

Post by ahull » Thu Dec 29, 2016 9:17 am

stevestrong wrote:Thanks, Andy, but this was copied from a working part of code.
I also tried your suggestion, but as expected, same "bug", it is something else there.

Btw, same code snippet works flawlessly if is executed on the main level, not within the ISR.
Interesting, what causes the interrupt?
Does the interrupt trigger, by definition only happen when the peripheral is effectively busy?
In other words, is waiting for interrupt service a condition that leaves the BSY peripheral register true?
Is the ISR responsible for clearing some flag or other to trigger BSY going false?
Are we entering the ISR too quickly, before the peripheral has time to settle?
Clearly we are missing some parts of the puzzle here.
- Andy Hull -

stevestrong
Posts: 2048
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: SPI interface freezes within the DMA ISR

Post by stevestrong » Thu Dec 29, 2016 9:44 am

The code accesses the SPI registers within DMA ISR. The ISR is entered when the DMA finished to transmit all bytes.

This is getting weird...Even disabling the SPI peripheral breaks the whole system...
Calling

Code: Select all

	spi_peripheral_disable(_currentSetting->spi_d);
within DMA ISR freezes the CPU, the USB serial is also blocked so that I can only close the serial monitor when I press the reset button on the blue pill board.

Hmmm...

stevestrong
Posts: 2048
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: SPI interface freezes within the DMA ISR

Post by stevestrong » Thu Dec 29, 2016 9:54 am

Just for reference, I attach here my code (dirty, full with debug lines, but good for testing)

Code: Select all

/*****************************************************************************/
void SPIClass::dmaSendIrq(void)
{
	digitalWrite(DEB, LOW);
	//chan_regs->CCR &= (DMA_CCR_EN_BIT|DMA_CCR_TCIE)^0xFFFFFFFF;
	bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 0); //dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);//
	bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_TCIE_BIT, 0);//dma_disable_irq(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);//
	//spi_tx_dma_disable(_currentSetting->spi_d);
	dmaIrqCount++;

if ( dmaIrqCount>1 ) {
	digitalWrite(DEB, HIGH);
	digitalWrite(DEB, LOW);
	spi_peripheral_disable(_currentSetting->spi_d); // here we have the freeze, the CPU will not execute the following lines...
	digitalWrite(DEB, HIGH);
	digitalWrite(DEB, LOW);
}
	digitalWrite(DEB, HIGH);
	while ( !spi_is_tx_empty(_currentSetting->spi_d) ); // "5. Wait until TXE=1 ..."
	digitalWrite(DEB, LOW);
	while ( spi_is_busy(_currentSetting->spi_d) ); // "... and then wait until BSY=0 before disabling the SPI." 
	digitalWrite(DEB, HIGH);
	//uint16 x = spi_rx_reg(_currentSetting->spi_d); // dummy read, needed, don't remove!
	uint8 tail = bufTail;
	// check if there is buffer available to send
	if ( tail!=bufHead ) { // data to be written available?
		// write window address
		writeWinAddr( dmaBuffer[tail].winAddr );
		// update length and memory to write from
		chan_regs->CMAR = (uint32)(&dmaBuffer[tail].color);//dma_set_mem_addr(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &dmaBuffer[bufTail].color);//
		chan_regs->CNDTR = dmaBuffer[tail].length;//dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, dmaBuffer[bufTail].length);//
		bufTail = (tail+1) & BUFF_SIZE_MASK;
		dmaSending = 1;
		writeCSActive(); // activate CS
	}
	else
	{	//nothing to send
		dmaSending = 0;
		writeCSIdle(); // release chip select
	}
	digitalWrite(DEB, LOW);
/**/
	dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
	if (dmaSending) {
		spi_tx_dma_enable(_currentSetting->spi_d);
		bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_TCIE_BIT, 1); // enable irq//dma_enable_irq(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);//
		bb_peri_set_bit(&chan_regs->CCR, DMA_CCR_EN_BIT, 1);//dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); // enable transmit
	}
	digitalWrite(DEB, HIGH);
}
What am I missing?

EDIT
The pasted function is first called from the main level, next time is called by the system when DMA finished to transmit the data.
Here a scope snapshot
SDS00001.jpg
SDS00001.jpg (51.95 KiB) Viewed 762 times
Yellow plot is the digital debug IO pin.
Blue plot is the SPI clock (SCK) output.
The long continuous blue section is the DMA sending to SPI output. Then, debug pin goes low (entering the ISR), then high->low sequence (dmaIrqCount>1), followed by the SPI disable function.
As you can see, the SPI disable line freezes the system...

User avatar
RogerClark
Posts: 7680
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: SPI interface freezes within the DMA ISR

Post by RogerClark » Thu Dec 29, 2016 10:20 am

@stevestrong

Do you have an Blue Pill you could turn into a BlackMagic Probe, as If the code has had an exception, its fairly easy to find out the what has caused the exception (which line of code) using GDB.

stevestrong
Posts: 2048
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: SPI interface freezes within the DMA ISR

Post by stevestrong » Thu Dec 29, 2016 10:26 am

Roger, if I manage to debug with STLink, how exactly can I detect the exception cause?
The code line causing the trouble is actually known. In fact, any SPI register access seems to cause this effect.
It must have to do with accessing within ISR, but I really cannot figure out what exactly can disturb so heavily...

User avatar
Pito
Posts: 1731
Joined: Sat Mar 26, 2016 3:26 pm
Location: Rapa Nui

Re: SPI interface freezes within the DMA ISR

Post by Pito » Thu Dec 29, 2016 11:51 am

For some configurations, disabling the SPI and entering the Halt mode while a transfer is ongoing can cause the current transfer to be corrupted and/or the BSY flag might become unreliable.

To avoid any of those effects, it is recommended to respect the following procedure when disabling the SPI:
http://stm32info.com/en/disabling-the-spi/

http://electronics.stackexchange.com/qu ... y-flag-set
Pukao Hats Cleaning Services Ltd.

zmemw16
Posts: 1674
Joined: Wed Jul 08, 2015 2:09 pm
Location: St Annes, Lancs,UK

Re: SPI interface freezes within the DMA ISR

Post by zmemw16 » Thu Dec 29, 2016 11:53 am

is it possible that it's 2 interrupts ?

set up a timer (with a silly limit) to force it out, just for debug only
hangs are so indeterminate :D

srp

Post Reply