Description
In cores/SERCOM.cpp, the SPI init function SERCOM::initSPI completely overwrites the value of the CTRLB register:
...
//Setting the CTRLB register
sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) |
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
...
In order to support hardware control of the SPI SS output, the MSSEN bit must be set in the CTRLB register. For example, on the Grand Central M4 board (SAMD51), pin 53 ('SS' signal) will be driven as a hardware controlled SS pin if the MSSEN bit is set in the corresponding SERCOM controller, in this case SERCOM7.
SERCOM7->SPI.CTRLB.reg|= SERCOM_SPI_CTRLB_MSSEN`
However, each call to SERCOM::InitSPI() as a result of the call to SPI.beginTransaction() clears the MSSEN bit, and leaves pin 53 disconnected.
One method (perhaps not the best one), is to preserve the existing state in the register. This must be done before the call to resetSPI(), which clears all the internal register, including CTRLB.
The completed function looks like this
void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder)
{
uint32_t ctrlb_image = sercom->SPI.CTRLB.reg;
resetSPI();
initClockNVIC();
#if defined(__SAMD51__)
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE(0x3) | // master mode
SERCOM_SPI_CTRLA_DOPO(mosi) |
SERCOM_SPI_CTRLA_DIPO(miso) |
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
#else
//Setting the CTRLA register
sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER |
SERCOM_SPI_CTRLA_DOPO(mosi) |
SERCOM_SPI_CTRLA_DIPO(miso) |
dataOrder << SERCOM_SPI_CTRLA_DORD_Pos;
#endif
//Setting the CTRLB register
sercom->SPI.CTRLB.reg = (ctrlb_image & SERCOM_SPI_CTRLB_MSSEN) |
SERCOM_SPI_CTRLB_CHSIZE(charSize) |
SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver.
while( sercom->SPI.SYNCBUSY.bit.CTRLB == 1 );
}
An explicit parameter could also be used to pass in the value in, but would affect higher layers of the SPI interface.