2018-02-20 10:26 AM
On an STM32F103RB, after switching the SPI1 from 8 bit to 16 bit the last byte received while still in 8 bit mode is received again in 16 bit mode.
SPI1 is configured as a plain master as follows:
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
SPI1->CR2 = 0;
SPI1->CR1 =
SPI_CR1_SSM |
SPI_CR1_SSI |
SPI_CR1_SPE |
BR_IDENT |
SPI_CR1_MSTR;�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
When then calling the rxblock() function below, the byte that has already been received in token() (as the first non-0xFF byte) is received once again in rxblock() and stored to the first location in *data. I verified this using a logic analyzer and found out that the byte is definitely not transmitted twice. For instance, a typical stream of bytes on MISO looks like this:
FF FF FF AA 00 00 00 00 00 00 00 00 00 ....
So the first 0xFF are discarded by token() until it receives and returns the 0xAA. The rxblock() should then only store a range of 0x00 to *data, but in fact I end up with the first byte of *data being 0xAA...
Even more funny, when I uncomment the sequence of bogus i++ statementsbelow (i being volatile to have an effect) everything works as expected and *data only contains 0x00 bytes.
Relevant source code:
static void flush(void)
{
/* Wait for SPI to complete */
while (!(SPI1->SR & SPI_SR_TXE));
while (SPI1->SR & SPI_SR_BSY);
(void) SPI1->DR;
}
static uint8_t token(uint32_t timeout)
{
flush();
for (uint8_t retry = 0; retry < 100; retry++) {
/* Send dummy 0xFF */
while (!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0xFF;
while (!(SPI1->SR & SPI_SR_RXNE));
uint8_t response = SPI1->DR;
if (response != 0xFF)
return response;
}
/* Timeout */
return 0xFF;
}
static bool rxblock(uint8_t *data, uint16_t n)
{
/* Wait for data start token */
if (token() != 0xAA)
return false;
//*
volatile uint8_t i = 0;
i++;
i++;
i++;
i++;
i++;
i++; //*/
/* Configure SPI in 16 bit mode with CRC */
flush();
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 |= (SPI_CR1_DFF | SPI_CR1_SPE);
/* Transfer */
(void) SPI1->DR;
for (uint16_t transfers = n / 2; transfers--; ) {
while ( !(SPI1->SR & SPI_SR_TXE) );
SPI1->DR = 0xFFFF;
while ( !(SPI1->SR & SPI_SR_RXNE) );
uint16_t word = SPI1->DR;
*data++ = word >> 8;
*data++ = word;
}
/* Restore 8 bit mode */
flush();
SPI1->CR1 &= ~SPI_CR1_SPE;
SPI1->CR1 &= ~SPI_CR1_DFF;
SPI1->CR1 |= SPI_CR1_SPE;
return true;
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
What am I missing?
Regards,
Sven
2018-02-22 08:17 AM
I haven't spent time to understand your problem fully, but if you have a suspicion that there is an internal flip/flop set which won't be cleared by disabling/enabling SPI, you may perhaps resort to extreme measures - resetting the SPI through the reset register in RCC.
JW