реклама на сайте
подробности

 
 
> STM32F3 SPI, Непонятное поведение
bseyur
сообщение Jul 1 2013, 11:10
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 65
Регистрация: 8-01-07
Из: Томск
Пользователь №: 24 208



Добрый день! Нужна помощь решении проблемы с SPI микроконтроллера STM32F303.

Начал работать с семейством 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 бит)

Если кто-то сталкивался с подобным поведением, подскажите, в каком направлении двигаться? sm.gif

Заполнение полей конфигурации для каждого устройства:
Код
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;


Настройка блока 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;


Процедура отправки 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));
    }


Процедура приема данных:
Код
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;
    }
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
adnega
сообщение Jul 1 2013, 11:52
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(bseyur @ Jul 1 2013, 15:10) *
Если кто-то сталкивался с подобным поведением, подскажите, в каком направлении двигаться? sm.gif

Многое зависит от того каким образом вы записываете данные в регистр DR.
Если число бит в посылке от 4 до 8, то к нему нужно обращаться как к байту (т.е. читать и писать uint8_t).
Если число бит в посылке от 9 до 16, то к нему нужно обращаться как к полуслову (т.е. читать и писать uint16_t).
Для этого в StdLib я поправил структуру для SPI:
CODE

/**
* @brief Serial Peripheral Interface
*/

typedef struct
{
__IO uint16_t CR1; /*!< SPI Control register 1 (not used in I2S mode), Address offset: 0x00 */
uint16_t RESERVED0; /*!< Reserved, 0x02 */
__IO uint16_t CR2; /*!< SPI Control register 2, Address offset: 0x04 */
uint16_t RESERVED1; /*!< Reserved, 0x06 */
__IO uint16_t SR; /*!< SPI Status register, Address offset: 0x08 */
uint16_t RESERVED2; /*!< Reserved, 0x0A */
union
{
__IO uint16_t DR16; /*!< SPI data register, Address offset: 0x0C */
__IO uint8_t DR8; /*!< SPI data register, Address offset: 0x0C */
};

uint16_t RESERVED3; /*!< Reserved, 0x0E */
__IO uint16_t CRCPR; /*!< SPI CRC polynomial register (not used in I2S mode), Address offset: 0x10 */
uint16_t RESERVED4; /*!< Reserved, 0x12 */
__IO uint16_t RXCRCR; /*!< SPI Rx CRC register (not used in I2S mode), Address offset: 0x14 */
uint16_t RESERVED5; /*!< Reserved, 0x16 */
__IO uint16_t TXCRCR; /*!< SPI Tx CRC register (not used in I2S mode), Address offset: 0x18 */
uint16_t RESERVED6; /*!< Reserved, 0x1A */
__IO uint16_t I2SCFGR; /*!< SPI_I2S configuration register, Address offset: 0x1C */
uint16_t RESERVED7; /*!< Reserved, 0x1E */
__IO uint16_t I2SPR; /*!< SPI_I2S prescaler register, Address offset: 0x20 */
uint16_t RESERVED8; /*!< Reserved, 0x22 */
} SPI_TypeDef;



В зависимости от разрядности обращаюсь либо к SPIx->DR8, либо SOIx->DR16.
Go to the top of the page
 
+Quote Post
bseyur
сообщение Jul 2 2013, 05:08
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 65
Регистрация: 8-01-07
Из: Томск
Пользователь №: 24 208



Цитата(adnega @ Jul 1 2013, 18:52) *
Многое зависит от того каким образом вы записываете данные в регистр DR.
.....

Действительно, как только я начал обращаться к регистру DR как к байту, все глюки ушли. Благодарю за наводку. sm.gif Порядок байт теперь также верный.
По правде говоря, сначала я посчитал эту версию несостоятельной, к примеру, чипы NXP честно отбрасывают лишние разряды. Но позже увидел такую расплывчатую формулировку:
Цитата
When the SPIx_DR register is accessed, data frames are always right-aligned
into either a byte (if the data fits into a byte) or a word (see Figure 293). During
communication, only bits within the data frame are clocked and transferred.

Спрашивается, для чего тогда необходимо поле Data size?
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- bseyur   STM32F3 SPI   Jul 1 2013, 11:10
- - bseyur   Благодарю за ответ! Завтра попробую.   Jul 1 2013, 12:09
- - Genadi Zawidowski   1) Как вы к data ragister будете обращаться ниаче,...   Jul 1 2013, 12:42
|- - adnega   Цитата(Genadi Zawidowski @ Jul 1 2013, 16...   Jul 1 2013, 12:45
|- - bseyur   Цитата(Genadi Zawidowski @ Jul 1 2013, 19...   Jul 1 2013, 13:12
|- - Genadi Zawidowski   Цитата(bseyur @ Jul 1 2013, 17:12) Изнача...   Jul 1 2013, 17:47
- - Golikov A.   ну как бы в литле ендиан сначала идет младший байт...   Jul 1 2013, 16:17
- - Golikov A.   Бились сегодня с подобной проблемой на LPC1678, ду...   Sep 13 2013, 20:08
|- - jcxz   А зачем? Если для ускорения, то гораздо лучше испо...   Sep 14 2013, 12:33
|- - bseyur   Цитата(Golikov A. @ Sep 14 2013, 03:08) Б...   Sep 16 2013, 08:36
- - Golikov A.   так там и есть ДМА, он 16 битными словами пихает п...   Sep 14 2013, 17:42
|- - jcxz   Я тоже пробовал (и на 1768 и на 1758), тоже не уда...   Sep 15 2013, 10:33
- - Golikov A.   похоже решения нет, только свапануть начальные мас...   Sep 15 2013, 11:45
- - Golikov A.   дело в том что unsigned int value = 0xAABB в памя...   Sep 16 2013, 09:21
- - bseyur   Понятно, здесь SSP как бы ни при чем. Правильно бу...   Sep 17 2013, 06:20


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 29th June 2025 - 04:16
Рейтинг@Mail.ru


Страница сгенерированна за 0.01387 секунд с 7
ELECTRONIX ©2004-2016