Начал работать с семейством STM32 впервые, до этого плотно заимался с продукцией NXP. Хоть и без негативных эмоций не обошлось, но на чипе без особых проблем удалось запустить ядро, USART, DMA, пару таймеров. А вот с SPI вошел в ступор.
Работаем в режиме мастера. Симптомы наблюдаются следующие:
1) При передаче блока длиной 16 бит в режиме "MSB first" первым почему-то уходит младший байт, затем старший. Такое впечатление, будто ядро little-endian, а блок SPI big-endian. Если это фича, то я не понял ее смысла.
2) SPI странно реагирует на установку размера блока данных (биты 8-11 в регистре CR2). Если в регистр записать значение (7<<8), что соответсвует 8 битам данных, в действительности блок содержит 16 бит. 8 бит можно получить, если установить значение 3<<8, 4 бит. Для эксперимента в регистр SPI->DR производится запись только 1 раз.
3) При попытке принять данные с внешнего устройства считанное значение не соответствует реальному.
Подозреваю, все три случая как-то связаны между собой, но уже не знаю, куда копать. Процедуру инициализации писал сам, глядя в даташит и stmlib, готовые функции используются только для инициализации портов в/в и включения тактовых клоков. На одном модуле SPI сидит 5 устройств, конфигурация у каждого своя, поэтому содержимое регистров CR1 и CR2 для них загружается из выделенных ранее переменных. Оптимизация выключена.
В момент записи в регистр DR конфигурация такая:
CR1 = 0x36F, установлены в 1 биты SPE SSM SSI MSTR CPOL CPHA, BR=5, остальные 0
CR2 = 0x700, все биты равны 0, кроме поля Data size (должно быть 8 бит)
Если кто-то сталкивался с подобным поведением, подскажите, в каком направлении двигаться?

Заполнение полей конфигурации для каждого устройства:
Код
TDeviceInfo* devinfo_ptr = SPIdeviceListPtr + device_id;
devinfo_ptr->CR1 = devinfo_ptr->CR2 = 0;
devinfo_ptr->CSEnablePtr = device_info->CSEnablePtr;
devinfo_ptr->CSDisablePtr = device_info->CSDisablePtr;
if (device_info->LSBFirst)
devinfo_ptr->CR1 |= SPI_FirstBit_LSB;
devinfo_ptr->CR1 |= device_info->BaudRateControl&(7UL<<3);
if (!device_info->SlaveMode)
devinfo_ptr->CR1 |= SPI_Mode_Master | SPI_NSS_Soft;
if (device_info->CPOL)
devinfo_ptr->CR1 |= SPI_CPOL_High;
if (device_info->CPHA)
devinfo_ptr->CR1 |= SPI_CPHA_2Edge;
devinfo_ptr->CR2 |= device_info->DataSize;
devinfo_ptr->CR1 = devinfo_ptr->CR2 = 0;
devinfo_ptr->CSEnablePtr = device_info->CSEnablePtr;
devinfo_ptr->CSDisablePtr = device_info->CSDisablePtr;
if (device_info->LSBFirst)
devinfo_ptr->CR1 |= SPI_FirstBit_LSB;
devinfo_ptr->CR1 |= device_info->BaudRateControl&(7UL<<3);
if (!device_info->SlaveMode)
devinfo_ptr->CR1 |= SPI_Mode_Master | SPI_NSS_Soft;
if (device_info->CPOL)
devinfo_ptr->CR1 |= SPI_CPOL_High;
if (device_info->CPHA)
devinfo_ptr->CR1 |= SPI_CPHA_2Edge;
devinfo_ptr->CR2 |= device_info->DataSize;
Настройка блока SPI:
Код
TDeviceInfo* devinfo_ptr = SPIdeviceListPtr + device_id;
SPI_TypeDef* SPIRegs;
if (SPINumber==SPIDRV_DEVICE1_INDEX)
SPIRegs = SPI1;
else if (SPINumber==SPIDRV_DEVICE2_INDEX)
SPIRegs = SPI2;
SPIRegs->CR1 &= ~SPI_CR1_SPE;
SPIRegs->CR1 = devinfo_ptr->CR1;
SPIRegs->CR2 = devinfo_ptr->CR2;
SPIRegs->CR1 = devinfo_ptr->CR1;
SPIRegs->CR2 &= ~SPI_CR2_DS;
SPIRegs->CR2 = devinfo_ptr->CR2;
SPIRegs->CR1 |= SPI_CR1_SPE;
SPI_TypeDef* SPIRegs;
if (SPINumber==SPIDRV_DEVICE1_INDEX)
SPIRegs = SPI1;
else if (SPINumber==SPIDRV_DEVICE2_INDEX)
SPIRegs = SPI2;
SPIRegs->CR1 &= ~SPI_CR1_SPE;
SPIRegs->CR1 = devinfo_ptr->CR1;
SPIRegs->CR2 = devinfo_ptr->CR2;
SPIRegs->CR1 = devinfo_ptr->CR1;
SPIRegs->CR2 &= ~SPI_CR2_DS;
SPIRegs->CR2 = devinfo_ptr->CR2;
SPIRegs->CR1 |= SPI_CR1_SPE;
Процедура отправки 16 бит данных в виде "2 раза по 8 бит":
Код
void CSPIDriver::SendData(uint16_t data)
{
SPI_TypeDef* SPIRegs;
if (SPINumber==SPIDRV_DEVICE1_INDEX)
SPIRegs = SPI1;
else if (SPINumber==SPIDRV_DEVICE2_INDEX)
SPIRegs = SPI2;
uint8_t byte1;
uint8_t byte2;
if ((SPIdeviceListPtr+CurrentDeviceID)->CR1&SPI_CR1_LSBFIRST)
{
byte1 = ((uint8_t*)&data)[0];
byte2 = ((uint8_t*)&data)[1];
}
else
{
byte1 = ((uint8_t*)&data)[1];
byte2 = ((uint8_t*)&data)[0];
}
while (SPIRegs->SR&SPI_SR_BSY);
while (SPIRegs->SR&SPI_SR_RXNE)
{volatile uint32_t dummy = SPIRegs->DR;}
SPIRegs->DR = byte1;
SPIRegs->DR = byte2;
while (!(SPIRegs->SR&SPI_SR_TXE));
}
{
SPI_TypeDef* SPIRegs;
if (SPINumber==SPIDRV_DEVICE1_INDEX)
SPIRegs = SPI1;
else if (SPINumber==SPIDRV_DEVICE2_INDEX)
SPIRegs = SPI2;
uint8_t byte1;
uint8_t byte2;
if ((SPIdeviceListPtr+CurrentDeviceID)->CR1&SPI_CR1_LSBFIRST)
{
byte1 = ((uint8_t*)&data)[0];
byte2 = ((uint8_t*)&data)[1];
}
else
{
byte1 = ((uint8_t*)&data)[1];
byte2 = ((uint8_t*)&data)[0];
}
while (SPIRegs->SR&SPI_SR_BSY);
while (SPIRegs->SR&SPI_SR_RXNE)
{volatile uint32_t dummy = SPIRegs->DR;}
SPIRegs->DR = byte1;
SPIRegs->DR = byte2;
while (!(SPIRegs->SR&SPI_SR_TXE));
}
Процедура приема данных:
Код
int32_t CSPIDriver::ReadMass(uint8_t* data, uint32_t count)
{
if (!data || !count)
return 0;
SPI_TypeDef* SPIRegs;
if (SPINumber==SPIDRV_DEVICE1_INDEX)
SPIRegs = SPI1;
else if (SPINumber==SPIDRV_DEVICE2_INDEX)
SPIRegs = SPI2;
while (SPIRegs->SR&SPI_SR_BSY);
while (SPIRegs->SR&SPI_SR_RXNE)
{volatile uint32_t dummy = SPIRegs->DR;}
uint32_t items_sent = 0;
uint32_t items_recieved = 0;
while (items_recieved<count)
{
while (items_sent<count && (SPIRegs->SR&SPI_SR_FTLVL)!=SPI_TransmissionFIFOStatus_Full)
{
SPIRegs->DR = 0xFF;
items_sent++;
}
while (SPIRegs->SR&SPI_SR_RXNE)
data[items_recieved++] = SPIRegs->DR;
}
return items_recieved;
}
{
if (!data || !count)
return 0;
SPI_TypeDef* SPIRegs;
if (SPINumber==SPIDRV_DEVICE1_INDEX)
SPIRegs = SPI1;
else if (SPINumber==SPIDRV_DEVICE2_INDEX)
SPIRegs = SPI2;
while (SPIRegs->SR&SPI_SR_BSY);
while (SPIRegs->SR&SPI_SR_RXNE)
{volatile uint32_t dummy = SPIRegs->DR;}
uint32_t items_sent = 0;
uint32_t items_recieved = 0;
while (items_recieved<count)
{
while (items_sent<count && (SPIRegs->SR&SPI_SR_FTLVL)!=SPI_TransmissionFIFOStatus_Full)
{
SPIRegs->DR = 0xFF;
items_sent++;
}
while (SPIRegs->SR&SPI_SR_RXNE)
data[items_recieved++] = SPIRegs->DR;
}
return items_recieved;
}