Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с SPI.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Jenya7
Камень STM32F303VC
Настроил SPI
Код
/*!< SPI Config */
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;  //APB1=36Mhz => ~1Mhz //APB2=72Mhz                                                                  
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_Init(SPIx, &SPI_InitStructure);

Размер задан - байт - SPI_DataSize_8b
На скопе на клоке вижу 16 бит - после передачи 8 бит посылает еще 8.
Я что то недонастроил?

Передача байта такая
Код
uint32_t SPI_TransferByte(SPI_TypeDef *SPIx, uint8_t data)
{
    uint32_t timeout;

    // All data transmitted/received but SPI may be busy so wait until done.
    timeout = SPI_DELAY;
    while (SPIx->SR & SPI_I2S_FLAG_BSY) { if(!timeout--) return SPI_ERR; }

    // Setting the Data Register (DR) transmits the byte of data on MOSI.
    SPIx->DR = data;

    //  Wait for any data on MISO pin to be received.
    timeout = SPI_DELAY;
    while (!(SPIx->SR & SPI_I2S_FLAG_RXNE)) { if(!timeout--) return SPI_ERR; }

    //  Return the data received on MISO pin.
    return (uint8_t)(SPIx->DR);
}
adnega
Цитата(Jenya7 @ Mar 27 2018, 09:53) *
Размер задан - байт - SPI_DataSize_8b
На скопе на клоке вижу 16 бит - после передачи 8 бит посылает еще 8.
Я что то недонастроил?

Есть такая тема в F3.
Перепишите структуру так
Код
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;

и для 8 и менее -битных посылках используйте SPIx->DR8, а для более 8-битных SPIx->DR16.

Добавлю, что это как раз тот случай, когда ответ можно найти в StdLib.
Код
void SPI_SendData8(SPI_TypeDef* SPIx, uint8_t Data)
{
  uint32_t spixbase = 0x00;

  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));

  spixbase = (uint32_t)SPIx;
  spixbase += 0x0C;
  
  *(__IO uint8_t *) spixbase = Data;
}


В RM это явление описано не очевидно.
Код
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 half-word (see Figure 388). During
communication, only bits within the data frame are clocked and transferred.
Jenya7
Цитата(adnega @ Mar 27 2018, 12:36) *
Есть такая тема в F3.

большое спасибо. я подозревал что ST намутили, но уверенности не было.
Сергей Борщ
QUOTE (adnega @ Mar 27 2018, 09:36) *
Добавлю, что это как раз тот случай, когда ответ можно найти в StdLib.
Глядя на этот код хочется долго и настойчиво бить его автора головой об стену.
Jenya7
Цитата(Сергей Борщ @ Mar 27 2018, 14:00) *
Глядя на этот код хочется долго и настойчиво бить его автора головой об стену.

а что в нем не так? на будущее. чтобы знать.
adnega
Цитата(Сергей Борщ @ Mar 27 2018, 12:00) *
Глядя на этот код хочется долго и настойчиво бить его автора головой об стену.

Я для себя ничего лучшего, чем подправить структуру не придумал.
Да, вмешался в исходник StdLib, что не допустимо.
Да, не все компиляторы поддерживают анонимные структуры/объединения.
Да, ST мальца накосячили.
Есть еще варианты кроме прямого приведения типов?
Сергей Борщ
QUOTE (Jenya7 @ Mar 27 2018, 11:23) *
а что в нем не так? на будущее. чтобы знать.
Поехали по буквам:
CODE
uint32_t spixbase = 0x00;
1)Придуманный специально для этого uintptr_t? Не, не слышали.
CODE
  spixbase = (uint32_t)SPIx;
  spixbase += 0x0C;
2)Магические числа. Ну хоть стандартный макрос offsetof() можно было использовать вместо магичесого числа? Не, не слышали.
3)Почему не смогли взять сразу адрес SPIx->DR? Адресная арифметика, которую компилятор делает лучше криворукого программиста, тут делается вручную.
4)Переменная называется spixbase, хотя хранит совсем не base.
CODE
  *(__IO uint8_t *) spixbase = Data;
Ну наконец-то! Полэкрана кода ради одного-единственного явного приведения типа.

А что мешало вместо всего этого "шедевра" написать один макрос
CODE
#define SPI_SendData8(SPIx, data)   *(__IO uint8_t *)&SPIx->DR = data
jcxz
Цитата(Сергей Борщ @ Mar 27 2018, 13:31) *
А что мешало вместо всего этого "шедевра" написать один макрос
Код
#define SPI_SendData8(SPIx, data)   *(__IO uint8_t *)&SPIx->DR = data

Полностью поддерживаю! Та функция - ну просто вырви-глаз какой-то! laughing.gif
Ещё лучше регистр DR описать как union 16-битного и 8-битного. Тогда будет выглядеть ещё лучше. Я обычно так делаю.

Честно говоря - мне всегда противно смотреть на портянки типа:
Код
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
...

всегда пролистываю такие сообщения не глядя.
И это вместо, того чтобы задать блоки периферийных регистров в виде структур, а формировать битовые поля в них макросами (ну или просто номерами битов), что было бы красиво и эффективно.
serglg
и куда ж такому "программисту" как я податься? :-)
Вот и вынужден пользоваться только чужими достижениями.
adnega
Цитата(serglg @ Mar 28 2018, 08:06) *
и куда ж такому "программисту" как я податься? :-)
Вот и вынужден пользоваться только чужими достижениями.

Научитесь читать на техническом английском, и перед вами откроются многообещающие перспективы.
serglg
Цитата(adnega @ Mar 28 2018, 11:38) *
Научитесь читать на техническом английском, и перед вами откроются многообещающие перспективы.


Еще освоить сам язык Си.
Obam
Цитата(jcxz @ Mar 27 2018, 15:13) *
...блоки периферийных регистров в виде структур, а формировать битовые поля в них макросами (ну или просто номерами битов), что было бы красиво и эффективно.

Символические имена, соответствующие даташиту или рефману, вместо "просто номеров битов" будут более красивы и существенно эффективны.
MrYuran
Чтобы не плодить тем, добавлю здесь.
Вчера у меня был фестиваль HardFault (
Зато вынес ценный опыт.

Ничто не предвещало..
Нажмите для просмотра прикрепленного файла

Тадамм!!
Нажмите для просмотра прикрепленного файла

В другом месте присвоение поля uint16_t в структуре падало так же, а копирование через memcpy проходило успешно.
Чтобы не мучать ребусами, обращаю внимание на адрес буфера данных.

HAL хорошая штука, но есть нюансы.
adnega
Цитата(MrYuran @ Mar 30 2018, 09:26) *
Чтобы не мучать ребусами, обращаю внимание на адрес буфера данных.

Типа данные не выровненные? А ядро какое?
На Cortex-M3 не выровненные данные не приводят к HF, а просто добавляют лишний такт (хотя можно заставить генерить исключение).
Вчера с аналогичной бедой боролся на Cortex-M0
Код
typedef struct s_param
{
    int    v_int;
} __attribute__((packed)) s_param;
...
((s_param *)&out[p_out])->v_int += (in[p_in] - '0');
MrYuran
Цитата(adnega @ Mar 30 2018, 09:49) *
Вчера с аналогичной бедой боролся на Cortex-M0

Вот оно же и есть. Там вкладочка с халом отсвечивает

Кстати, если бы не криворукий пейсатель драйвера AD7799 c сайта analog.com, я бы никогда туда не залетел.
Они там в первый байт буфера кидают какой-то служебный байт, пришлось сдвинуть на один и здрасте.
jcxz
Цитата(Obam @ Mar 28 2018, 18:18) *
Символические имена, соответствующие даташиту или рефману, вместо "просто номеров битов" будут более красивы и существенно эффективны.

Ну да, ну да. Как же. Всё в мире относительно.
Вот например набор символических имён только для одного из регистров USIC в XMC4xxx:
CODE
#define USIC_CH_RBCTR_DPTR_Pos
#define USIC_CH_RBCTR_DPTR_Msk
#define USIC_CH_RBCTR_LIMIT_Pos
#define USIC_CH_RBCTR_LIMIT_Msk
#define USIC_CH_RBCTR_SRBTM_Pos
#define USIC_CH_RBCTR_SRBTM_Msk
#define USIC_CH_RBCTR_SRBTEN_Pos
#define USIC_CH_RBCTR_SRBTEN_Msk
#define USIC_CH_RBCTR_SRBINP_Pos
#define USIC_CH_RBCTR_SRBINP_Msk
#define USIC_CH_RBCTR_ARBINP_Pos
#define USIC_CH_RBCTR_ARBINP_Msk
#define USIC_CH_RBCTR_RCIM_Pos
#define USIC_CH_RBCTR_RCIM_Msk
#define USIC_CH_RBCTR_SIZE_Pos
#define USIC_CH_RBCTR_SIZE_Msk
#define USIC_CH_RBCTR_RNM_Pos
#define USIC_CH_RBCTR_RNM_Msk
#define USIC_CH_RBCTR_LOF_Pos
#define USIC_CH_RBCTR_LOF_Msk
#define USIC_CH_RBCTR_ARBIEN_Pos
#define USIC_CH_RBCTR_ARBIEN_Msk
#define USIC_CH_RBCTR_SRBIEN_Pos
#define USIC_CH_RBCTR_SRBIEN_Msk
#define USIC_CH_RBCTR_RBERIEN_Pos
#define USIC_CH_RBCTR_RBERIEN_Msk

Теперь представьте, что для того чтобы сконфигурить этот самый USIC в режиме UART надо записать значения в пару десятков его регистров.
И для каждого - подобная портянка.
С "символическими именами" портянка получается очень даже зубодробительная - чёрт ногу сломит в таких портянках.
И какой смысл от неё? Если битов десяток - то ещё можно запомнить, что значит каждое из этих имён, но когда в этой периферии регистров - несколько десятков, да в каждом - до 32 конфигурационных битов - один фиг без pdf перед глазами не вспомнить их назначение. А по мануалу гораздо удобнее искать по номерам битов чем по этим зубодробительным именам.
Лучше уж я напишу:
Код
      io->RBCTR = ch + UART_FIFO_TX_SIZE |
      UART_FIFO_RX_SIZE / 2 - 1 << 8 | (srTxRxErr & 7 << 3) << 16 - 3 |
      srTxRxErr >> 6 << 19 | 3 << 22 |
      concat(USIC_FIFO_SIZE_, UART_FIFO_RX_SIZE) << 24 |
      B15 | B28 | B30 | B31;
А когда надо что-то поменять - всё равно залезу в мануал.
PS: Так что не надо всё мерить по STM32 с его скудной периферией в 2-3 регистра. laughing.gif
Obam
Хозян, как всем известно - барин...
да и речь в топике велась об "STM32 с его скудной периферией в 2-3 регистра."

Цитата
На Cortex-M3 не выровненные данные не приводят к HF...

В командах STM/LDM не выровненные на границу слова данные ещё как приводят.
jcxz
Цитата(Obam @ Mar 30 2018, 17:55) *
В командах STM/LDM не выровненные на границу слова данные ещё как приводят.

и не только в них...
Только как и Вы сами выше не преминули заметить, замечу что речь велась об операции *(uint16_t *)pData, кою компилятор ну никак не мог превратить ни в LDM/STM ни в LDRD/STRD ни во что другое кроме как LDRH, которая на M3 не подвержена HF cool.gif

PS: А автору полезно было-бы завести типы для работы с невыровненными данными например:
Код
typedef __packed u16 u16p8;
typedef __packed s16 s16p8;
typedef __packed u32 u32p8;
typedef __packed s32 s32p8;
typedef __packed u64 u64p8;
typedef __packed s64 s64p8;
typedef __packed u32 u32p16;
typedef __packed s32 s32p16;
typedef __packed u64 u64p16;
typedef __packed s64 s64p16;
typedef __packed u64 u64p32;
typedef __packed s64 s64p32;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.