Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32L4 прерывания от UART. Закипел.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Димон Безпарольный
Пишу код под Nucleo L476. Кубом. И вручную. Результат тот же. Поднял UART1. UART работает. Но прерываний нет. Ни в коде от Куба ни в моем коде.
Вручную настраивал так:
Код
    USART1->CR1 =    1<<7 |                        //Bit 7 TXEIE: interrupt enable
                    1<<6 |                        //Bit 6 TCIE: Transmission complete interrupt enable
                    1<<5 |                        //Bit 5 RXNEIE: RXNE interrupt enable
                    1<<3 |                        //Bit 3 TE: Transmitter enable
                    1<<2 |                        //Bit 2 RE: Receiver enable
                    1<<0;                         //Bit 0 UE: USART enable
    USART1->CR2 =    1<<11;                         //Bit 11 CLKEN: Clock enable
    USART1->BRR =     0x271;                        //Tx/Rx baud =     f CK / BRR.  Oversampling by 16


Если выполнить макрос, разрешающий 37-е прерывание:
Код
NVIC->ISER[(((uint32_t)(int32_t)37) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)(int32_t)37) & 0x1FUL));


То в моем варианте все виснет. Точно такой же макрос с параметром 37 есть в коде от Куба. Но он не вешает систему. Прерываний просто нет. И да, прерывания от SYSTIC работают в обоих случаях.
Мож кто подскажет в чем дело или примерчик рабочий... Хотя под L476 я мало чего нахожу в Сети.
Сергей Борщ
QUOTE (Димон Безпарольный @ May 11 2016, 11:05) *
То в моем варианте все виснет
Вот просто напрочь виснет? И даже отладчик перестает отзываться?
Димон Безпарольный
Цитата(Сергей Борщ @ May 11 2016, 11:28) *
Вот просто напрочь виснет? И даже отладчик перестает отзываться?

Нет, отладчик работает. Я сейчас в нем ковыряюсь.
Сергей Борщ
QUOTE (Димон Безпарольный @ May 11 2016, 11:57) *
Нет, отладчик работает.
Тогда что вы вкладываете в понятие "виснет"? Процессор же не может ничего не делать (если не спит). Он должен выполнять какие-то команды. Могу телепатически предположить, что у вас в соответствующий вектор не прописан адрес вашего обработчика и поэтому ядро улетает в общий обработчик, который обычно состоит из пустого цикла.
scifi
Цитата(Димон Безпарольный @ May 11 2016, 11:57) *
Нет, отладчик работает. Я сейчас в нем ковыряюсь.

Отладчик позволяет увидеть всё: UART, NVIC, процессор. Соответственно, без особого труда можно пройтись по всей цепочке и установить, что именно сработало не так.
Поэтому да, лучше ковыряйтесь в отладчике, чем в форуме laughing.gif
Димон Безпарольный
Цитата(Сергей Борщ @ May 11 2016, 12:15) *
Тогда что вы вкладываете в понятие "виснет"? Процессор же не может ничего не делать (если не спит). Он должен выполнять какие-то команды. Могу телепатически предположить, что у вас в соответствующий вектор не прописан адрес вашего обработчика и поэтому ядро улетает в общий обработчик, который обычно состоит из пустого цикла.

Не улетает. Я по зажиганию светодиода сужу. Виснет это как раз когда не выполняются основной процесс и SysTic. Опять же по светодиоду могу сказать что в исключениях процессор тоже не был. Где он присутствует пока сказать не могу. Вектора все прописаны. Проверял. В ISER[1] ставил пятый бит вручную - не помогло.


Меня в меньшей степени интересует собственный код. Т.е. где виснет. Меня интересует код от Куба, где не виснет но и не выполняется код прерывания от UART. Его я ковыряю.

Не пойму я состояние. ISER1 - пятый бит установлен(прерывание 37). Он тут же ставится и в ICER1. После загрузки TDR регистра, передача байта идет исправно, но прерывания в Pending регистрах нет. И прерывания нет. Чего ж я все - таки забыл сделать?

Чертова документация. PM0214, Generic User Guide, RM0351 аж о 1600 страницах! Ни в одном нет полного описания регистров NVIC. Что ж за регистр ICTR и STIR которые есть в отладчике, но нет ни в одной документации.

Код:
Код
        USART1->TDR = 0x65;
        USART1->TDR = 0x85;

Передает только первый байт. ОК.

Код:
Код
        USART1->TDR = 0x65;
        while((USART1->ISR & (1<<6)) == 0) {};
        USART1->TDR = 0x85;


Передает оба байта. Значит бит TC: Transmission complete (или можно бит 7 Transmit data register empty) работает исправно. Прерывание по нему разрешено. Но нихрена не выполняется.

Прочитал регистр USART1->CR1. Окаывается Куб не выставил бит разрешения прерывания (бит 6).

Победил и прием. Была проблема при отключении HAL_UART_IRQHandler(&huart1);. Я не понимаю как это возможно, но отключить эту функцию не так просто. Без нее тоже висло намертво. Даже при очистке функции до пустых скобок. И только отключив оптимизатор я смог избавится от этой дряни. Вот код на прием и передачу. Работает.
Код
void USART1_IRQHandler(void)
{

/* USER CODE BEGIN USART1_IRQn 0 */
        if(Led) {Led=0;    GPIOA->BSRR = 32;}
        else {Led=1;    GPIOA->BSRR = (32<<16);}
        if (USART1->ISR & (1<<6)) {USART1->ICR  |=(1<<6);}
        if (USART1->ISR & (1<<5)) {USART1->ICR  |=(1<<5); USART1->TDR = USART1->RDR;}
        //USART1->ICR |= (1<<6);


    /* USER CODE END USART1_IRQn 0 */
  //HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}


Не понимаю почему я должен читать ISR: USART1->ISR & (1<<6) тогда как по смыслу правильнее было бы читать ICR. И чтение там допускается. Но опять же не работает нихрена - виснет.
В коде мало смысла, но для понимания работы пойдет. Оказывается Кубу не досуг ставить биты разрешения прерываний на прием и передачу. Пришлось самому. Ручками:
Код
      USART1->CR1 |= (1<<6);    //translate
      USART1->CR1 |= (1<<5);    //recieve


Всем спасибо за помощь. rolleyes.gif
Lagman
А такая команда отправляет буфер?
Код
HAL_UART_Transmit_IT(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE);

Для этой платы есть несколько примеров c UART(USART) от ST, и с прерыванием, и с DMA, и простой передачей, и с просыпанием от UARTA и не верится что они там ошиблись.
Димон Безпарольный
Цитата(Lagman @ May 11 2016, 23:31) *
А такая команда отправляет буфер?
Код
HAL_UART_Transmit_IT(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE);

Для этой платы есть несколько примеров c UART(USART) от ST, и с прерыванием, и с DMA, и простой передачей, и с просыпанием от UARTA и не верится что они там ошиблись.

Они может и не ошиблись, но Куб не ставит 5 и 6 бит на прерывания. Хотя я галочку в Кубе ставил на Global Interrupt Usart1. Да и где ему ставить если:

Код
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  HAL_UART_Init(&huart1);
x893
То есть они весь мир обманули с примером UART_TwoBoards_ComIT ?
Срочно напишите им - пусть исправят немедленно.
ViKo
Забейте на Куб. Он не для работы. А для демонстрации работоспособности.
Я запрограммировал регистры USART одной функцией, и все работает, по прерыванию, естественно. Не в данном МК, но разница невелика.
KnightIgor
Цитата(Димон Безпарольный @ May 11 2016, 10:43) *
Не понимаю почему я должен читать ISR: USART1->ISR & (1<<6) тогда как по смыслу правильнее было бы читать ICR. И чтение там допускается. Но опять же не работает нихрена - виснет.

В этой фразе - иллюстрация не полного понимания работы устройства. Это не в упрёк, - все были новичками, - это для анализа ошибок.
ISR - регистр СТАТУСА (status), ICR - регистр УПРАВЛЕНИЯ (control). Биты последнего можно читать, да, но они не устанавливаются как результат работы устройства, а потому не отображают его состояния. Для этого есть регистр статуса, и пусть не смущает, что расположение битов в этих регистрах может совпадать и таким образом вводить в заблуждение.
Димон Безпарольный
Цитата(ViKo @ May 12 2016, 12:03) *
Забейте на Куб. Он не для работы. А для демонстрации работоспособности.
Я запрограммировал регистры USART одной функцией, и все работает, по прерыванию, естественно. Не в данном МК, но разница невелика.

Для этого я и ковырял Куб, чтобы понять суть и сделать уже свой проект. Без излишиств и недостатков. В итоге все получилось.

Off. Достал меня Эклипс. Не смог прикрутить PrintF. Кейловские технологии не прокатили. Буду переходить на Кейл.
Tanya
Цитата(Димон Безпарольный @ May 12 2016, 14:18) *
Для этого я и ковырял Куб, чтобы понять суть и сделать уже свой проект.

Работает Куб. У меня. Читать нужно внимательно. Переписывать или свое прерывание писать там не предполагается. А писать нужно в callback-функцию. Там их, кажется мне, две - половинное и полное завершение. И, соответственно, два раза прерывание вызывается. И эти функции.
Димон Безпарольный
Цитата(Tanya @ May 12 2016, 16:50) *
Работает Куб. У меня. Читать нужно внимательно. Переписывать или свое прерывание писать там не предполагается. А писать нужно в callback-функцию. Там их, кажется мне, две - половинное и полное завершение. И, соответственно, два раза прерывание вызывается. И эти функции.

В посте 8 я привел настройки uart1. Про 5 и 6 бит там не упоминается. Соответственно без них прерывания на прием и передачу работать не будут. Приведите свой код если Вы утверждаете что эти биты устанавливаются.
MrYuran
Цитата(Димон Безпарольный @ May 12 2016, 14:18) *
Off. Достал меня Эклипс. Не смог прикрутить PrintF. Кейловские технологии не прокатили. Буду переходить на Кейл.

Вот интересно, какая связь между эклипсом и printf()
Tanya
Цитата(Димон Безпарольный @ May 12 2016, 17:41) *
В посте 8 я привел настройки uart1. Про 5 и 6 бит там не упоминается. Соответственно без них прерывания на прием и передачу работать не будут. Приведите свой код если Вы утверждаете что эти биты устанавливаются.

Если найду - перешла на ДМА... Прерывание должно разрешаться при старте... что-то там... HAL_UART_Receive_IT
Естественно, после завершения прерывания должны отключаться.
Димон Безпарольный
Цитата(MrYuran @ May 12 2016, 18:48) *
Вот интересно, какая связь между эклипсом и printf()

Прямая. Под Кейлом я знаю как printF прикрутить:
Код
_ARMABI int printf(const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1)));
struct __FILE { int handle;};
FILE __stdout;
int fputc(int ch, FILE *f)


А под Эклиспом это не работает.
x893
Цитата(Димон Безпарольный @ May 12 2016, 19:47) *
Прямая. Под Кейлом я знаю как printF прикрутить:
Код
_ARMABI int printf(const char * __restrict /*format*/, ...) __attribute__((__nonnull__(1)));
struct __FILE { int handle;};
FILE __stdout;
int fputc(int ch, FILE *f)


А под Эклиспом это не работает.

Овладел телепатией !
Под эклипсом используете gcc, а под Keil - armcc !!!
scifi
Цитата(x893 @ May 12 2016, 21:13) *
Овладел телепатией !
Под эклипсом используете gcc, а под Keil - armcc !!!

Ага. В сознании трудящихся текстовый редактор и компилятор слились воедино. Скоро будет "розовый компутер - для кортексов, серенький - для авр". Ждём притока блондинок в отрасль cranky.gif
Димон Безпарольный
Цитата(x893 @ May 12 2016, 21:13) *
Овладел телепатией !
Под эклипсом используете gcc, а под Keil - armcc !!!

Хорошо унизили.

OK. Под AVR Studio кажется тоже GCC. Но и этот вариант не прокатил.
x893
Цитата(Димон Безпарольный @ May 12 2016, 21:23) *
Хорошо унизили.

OK. Под AVR Studio кажется тоже GCC. Но и этот вариант не прокатил.

Даже в мыслях не было.
Можно gcc под Keil и armcc под эклипсом.
Но тогда бы printf с fputc под эклипсом работал, а под Keil - нет.
Димон Безпарольный
В общем в Кейле это работает:

Код
struct __FILE {int dummy;};
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)


А в Эклипсе я разные варианты пробовал - безуспешно. Но Кейл мне больше нравится и по другим причинам...
Димон Безпарольный
Чертов Куб. Пытался SPI поднять. Поднял блин. В коде не нашел где конфигурируются пины SPI.

Здесь:
Код
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_9BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_HARD_OUTPUT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 7;
  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  HAL_SPI_Init(&hspi2);


нет.
В MX_GPIO_Init тоже нет.
Aleksandr Baranov
Цитата(Димон Безпарольный @ May 13 2016, 09:02) *
Чертов Куб. Пытался SPI поднять. Поднял блин. В коде не нашел где конфигурируются пины SPI.


А так не получится?
Код
   //PB10: SPI2_CLK, PB14: SPI2_MISO, PB15: SPI2_MOSI
  GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
  GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
  GPIO_InitStructure.Mode  = GPIO_MODE_AF_PP;
  GPIO_InitStructure.Speed = GPIO_SPEED_MEDIUM,
  GPIO_InitStructure.Pull  = GPIO_NOPULL,
  GPIO_Init(GPIOB, &GPIO_InitStructure);


PS. Вот, специально куб запустил для эксперимента:

Код
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi){
  GPIO_InitTypeDef GPIO_InitStruct;
  if(hspi->Instance==SPI1)
  {
    /* Peripheral clock enable */
    __SPI1_CLK_ENABLE();
  
  /**SPI1 GPIO Configuration  
  PA5   ------> SPI1_SCK
  PA6   ------> SPI1_MISO
  PA7   ------> SPI1_MOSI
  */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi){
  if(hspi->Instance==SPI1)
  {
    /* Peripheral clock disable */
    __SPI1_CLK_DISABLE();
  
  /**SPI1 GPIO Configuration  
  PA5   ------> SPI1_SCK
  PA6   ------> SPI1_MISO
  PA7   ------> SPI1_MOSI
  */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);

  }
}
Димон Безпарольный
Цитата(Aleksandr Baranov @ May 13 2016, 17:10) *
А так не получится?
Код
   //PB10: SPI2_CLK, PB14: SPI2_MISO, PB15: SPI2_MOSI
  GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
  GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
  GPIO_InitStructure.Mode  = GPIO_MODE_AF_PP;
  GPIO_InitStructure.Speed = GPIO_SPEED_MEDIUM,
  GPIO_InitStructure.Pull  = GPIO_NOPULL,
  GPIO_Init(GPIOB, &GPIO_InitStructure);


PS. Вот, специально куб запустил для эксперимента:

У меня нет функции HAL_SPI_MspDeInit. Только пустой ее вариант со слабым связыванием.

Не получается почему - то даже вот так:

Код
  GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  

  GPIO_InitStruct.Pin = GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);


Выводы остаются почему - то висячими. Я нихрена не понимаю. Но если их назначть как выходные (01), то ими можно повертеть. Только SPI блок ими вертеть не хочет.
Я и сам пробовал - результат тоот же!

Код
    RCC->APB1ENR1 |= 1<<14;                    //Тактирование SPI2 стр. 228
    for (i = 0; i < 30000; i++ ){};
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOBEN;    //Разрешить тактирование GPIOB
    for (i = 0; i < 30000; i++ ){};
    RCC->AHB2ENR |= RCC_AHB2ENR_GPIOCEN;    //Разрешить тактирование GPIOC
    for (i = 0; i < 30000; i++ ){};
    GPIOB->MODER =     (2<<20)|                //PB10 - альтернативная функция SPI2_SCK
                    (2<<24)|                //PB12 - альтернативная функция SPI2_NSS
                    (1<<26);                 //PB13 - Программный CS push pull режим
    GPIOC->MODER =     (2<<6);                    //PC3 - альтернативная функция SPI2_MOSI
    GPIOB->AFR[1] = 5<<8|                    //Альтернативная функция 5 для PB10 стр. 268
                    5<<16;                    //Альтернативная функция 5 для PB12
    GPIOC->AFR[0] = 5<<12;                    //Альтернативная функция 5 для PC3

//PB10 = SPI2_SCK = AF5
//PB12 = SPI2_NSS = AF5
//PB13 = Soft NSS output push pull.
//PC3 = SPI2_MOSI = AF5

    SPI2->CR1 = 0<<0|    //Bit 0 CPHA: Clock phase
                0<<1|    //Bit1 CPOL: Clock polarity
                1<<2|    //Bit 2 MSTR: Master selection
                7<<3|    //Bits 5:3 BR[2:0]: Baud rate control 000b=2,001b=4,010b=8,011b=16,100b=32,101b=64,110b=128,111b=256
                1<<6|    //Bit 6 SPE: SPI enable
                0<<7|    //Bit 7 LSBFIRST: Frame format 0-MSB First
                0<<8|    //Bit 8 SSI: Internal slave select
                0<<9|    //Bit 9 SSM: Software slave management
                0<<10|    //Bit 10 RXONLY: Receive only mode enabled
                0<<11|    //Bit 11 CRCL: CRC length
                0<<12|    //Bit 12 CRCNEXT: Transmit CRC next
                0<<13|    //Bit 13 CRCEN: Hardware CRC calculation enable
                1<<14|    //Bit 14 BIDIOE: Output enable in bidirectional mode
                0<<15;    //Bit 15 BIDIMODE: Bidirectional data mode enable
    SPI2->CR2 = 0<<0|    //RXDMAEN: Rx buffer DMA enable
                0<<1|    //Bit 1 TXDMAEN: Tx buffer DMA enable
                1<<2|    //Bit 2 SSOE: SS output enable
                1<<3|    //Bit 3 NSSP: NSS pulse management
                0<<4|    //Bit 4 FRF: Frame format 0: SPI Motorola mode, 1 SPI TI mode
                0<<5|    //Bit 5 ERRIE: Error interrupt enable
                0<<6|    //Bit 6 RXNEIE: RX buffer not empty interrupt enable
                0<<7|    //Bit 7 TXEIE: Tx buffer empty interrupt enable
                8<<8|    //Bits 11:8 DS [3:0]: Data size. 8 - 9бит
                0<<12|    //Bit 12 FRXTH: FIFO reception threshold
                0<<13|    //Bit 13 LDMA_RX: Last DMA transfer for reception
                0<<14;    //Bit 14 LDMA_TX: Last DMA transfer for transmission
Lagman
Не знаю что у вас там за проблемы, но если использовать связку CubeMX с установленными пакетами под нужное семейство (например STM32CubeF0) и System Workbench for STM32, понимая идеологию HAL все можно сделать не вчитываясь в даташит на микроконтроллер.

Попробуйте обновить все программы и пакеты, и посмотреть примеры которые идут в пакетах (под каждое семейство свой пакет, вручную скачать с st и открыть архив) для CubeMX.
x893
Нормально Куб генерирует всё. Надо птички/галки ставить где надо. И под прерывания генерит.
Один минус чуть больше кода получается, но это можно потом пооптимизировать.
Lagman
Может еще вот это мешает.
Некоторые контроллеры имеют функции блокировки изменения конфигурации пинов, для RX например чтобы включить альтернативные функции на ногу, то надо записать определенные битики в определенный регистр, после чего можно переконфигурировать выводы. Для STM32F0 например есть такой регистр "GPIO port configuration lock register". И если вы хотите, после того как Куб сгенерировал код для проекта, в ходе работы поменять функции для пина тогда надо искать как это работает в этом семействе, потому что для F0 написано что если залочить то тогда только до перезагрузки, а Куб может генерирует так что лочит их при инициализации (посмотрел в простом проекте, по умолчанию не лочит).
Для L4 в даташите тоже есть такие строчки:
Цитата
7.3.6 GPIO locking mechanism
It is possible to freeze the GPIO control registers by applying a specific write sequence to
the GPIOx_LCKR register. The frozen registers are GPIOx_MODER, GPIOx_OTYPER,
GPIOx_OSPEEDR, GPIOx_PUPDR, GPIOx_AFRL and GPIOx_AFRH.


В HAL есть такая функция HAL_GPIO_LockPin
SSerge
Цитата(Димон Безпарольный @ May 11 2016, 15:05) *
Пишу код под Nucleo L476. Кубом. И вручную. Результат тот же. Поднял UART1. UART работает. Но прерываний нет. Ни в коде от Куба ни в моем коде.
Вручную настраивал так:
Код
    USART1->CR1 =    1<<7 |                        //Bit 7 TXEIE: interrupt enable
                    1<<6 |                        //Bit 6 TCIE: Transmission complete interrupt enable
                    1<<5 |                        //Bit 5 RXNEIE: RXNE interrupt enable
                    1<<3 |                        //Bit 3 TE: Transmitter enable
                    1<<2 |                        //Bit 2 RE: Receiver enable
                    1<<0;                         //Bit 0 UE: USART enable
    USART1->CR2 =    1<<11;                         //Bit 11 CLKEN: Clock enable
    USART1->BRR =     0x271;                        //Tx/Rx baud =     f CK / BRR.  Oversampling by 16

А зачем во время инициализации разрешать прерывания TXEIE и TCIE ? Зачем прерывание если нечего передавать?
Когда потребуется что-то передавать, вот тогда и разрешите TXEIE, а когда возникнет желание узнать что все передаваемые данные, до последнего бита ушли и передавать больше нечего, вот тогда во время записи последнего байта в DR и следует разрешить TCIE.
Это если всё руками делать, а если положиться на Куб, то он прерываниями сам рулит.

А CLKEN зачем?
Димон Безпарольный
Цитата(Lagman @ May 14 2016, 11:44) *
Для STM32F0 например есть такой регистр "GPIO port configuration lock register". И если вы хотите, после того как Куб сгенерировал код для проекта, в ходе работы поменять функции для пина тогда надо искать как это работает в этом семействе, потому что для F0 написано что если залочить то тогда только до перезагрузки, а Куб может генерирует так что лочит их при инициализации (посмотрел в простом проекте, по умолчанию не лочит).
Для L4 в даташите тоже есть такие строчки:


В HAL есть такая функция HAL_GPIO_LockPin

Есть такой регистр:
Цитата
the value of this port bit can no longer be modified until the next MCU reset or peripheral reset.


Но я спокойно назначаю эти выводы как выходные и также спокойно ими верчу.

Только SPI модуль ими не хочет вертеть. Как только я включаю Alternate Function, все выводы переключаются в третье состояние.

Цитата(SSerge @ May 14 2016, 12:25) *
А зачем во время инициализации разрешать прерывания TXEIE и TCIE ? Зачем прерывание если нечего передавать?
Когда потребуется что-то передавать, вот тогда и разрешите TXEIE, а когда возникнет желание узнать что все передаваемые данные, до последнего бита ушли и передавать больше нечего, вот тогда во время записи последнего байта в DR и следует разрешить TCIE.
Это если всё руками делать, а если положиться на Куб, то он прерываниями сам рулит.

А CLKEN зачем?

CLKEN не нужен. Точно. И с прерываниями Вы правы на все 100. Нужно было срочно сваять кольцевые буфера, printf, плавучку. Не обратил внимание.

Цитата(x893 @ May 14 2016, 11:12) *
Нормально Куб генерирует всё. Надо птички/галки ставить где надо. И под прерывания генерит.
Один минус чуть больше кода получается, но это можно потом пооптимизировать.

Вот как раз галочку на прерывание от USART я и поставил. Но прерывания были запрещены. Лажа этот куб. Ручками быстрее получилось.
Димон Безпарольный
Бит 2 не ставится! Читаю значение i=SPI2->CR1;, вывожу - 16440 = 100000000111000. Нет бита 2 - матстер.

Ставлю повторно - ни в какую.

Может из - за Mode fault (MODF):

Цитата
The MSTR bit is cleared, thus forcing the device into slave mode.


Точно из-за него. 1100000100000 пятый бит MODF. Черти, навертели всякой хрени.
Lagman
Цитата(Димон Безпарольный @ May 14 2016, 20:28) *
Только SPI модуль ими не хочет вертеть. Как только я включаю Alternate Function, все выводы переключаются в третье состояние.

Опишите что Вы хотите получить в принципе, как конфигурируете, в CubeMX, модуль SPI и выводы, и что потом с ними хотите сделать в System Workbench.
Димон Безпарольный
Цитата(Lagman @ May 14 2016, 22:12) *
Опишите что Вы хотите получить в принципе, как конфигурируете, в CubeMX, модуль SPI и выводы, и что потом с ними хотите сделать в System Workbench.

Я хочу с ним сделать в Кейле.
SPI2. Мастер только, без прерываний, 9 бит, Clock phase = 0, Clock polarity = 0. Внутренний генератор HSE, частота процессора 80МГц(PLL), PA5 - на вывод для мигалки. Скорость SPI не важна.

Процессор STM32L476RG

Куб конфигурирует SPI выводы так:
//PB10 = SPI2_SCK = AF5
//PB12 = SPI2_NSS = AF5
//PC3 = SPI2_MOSI = AF5

Не могу выставить биты 2(MSTR: Master selection) и 6(SPE: SPI enable) - их сбрасывает проклятый MODF даже после первого обращения к SPI - записи в CR1.

Код
    SPI2->CR1 = 0<<0|    //Bit 0 CPHA: Clock phase
                0<<1|    //Bit1 CPOL: Clock polarity
                1<<2|    //Bit 2 MSTR: Master selection
                0<<3|    //Bits 5:3 BR[2:0]: Baud rate control 000b=2,001b=4,010b=8,011b=16,100b=32,101b=64,110b=128,111b=256
                1<<6|    //Bit 6 SPE: SPI enable
                0<<7|    //Bit 7 LSBFIRST: Frame format 0-MSB First
                0<<8|    //Bit 8 SSI: Internal slave select
                0<<9|    //Bit 9 SSM: Software slave management
                0<<10|    //Bit 10 RXONLY: Receive only mode enabled
                0<<11|    //Bit 11 CRCL: CRC length
                0<<12|    //Bit 12 CRCNEXT: Transmit CRC next
                0<<13|    //Bit 13 CRCEN: Hardware CRC calculation enable
                0<<14|    //Bit 14 BIDIOE: Output enable in bidirectional mode
                0<<15;    //Bit 15 BIDIMODE: Bidirectional data mode enable

Короче как только разрешаю мастер, сразу выставляется modf.
Или по - другому. Можно не разрешать SPI, тогда мастер ставится.

Чего - то перестарались господа - навертели хрен знает чего в камень.

Почему может ставится этот бит? В документации сказано:

Цитата
Mode fault occurs when the master device has its internal NSS signal (NSS pin in NSS
hardware mode, or SSI bit in NSS software mode) pulled low. This automatically sets the
MODF bit.


Но выходы на плате я поверял - они в третьем состоянии.
Lagman
Цитата(Димон Безпарольный @ May 14 2016, 22:40) *
Я хочу с ним сделать в Кейле.
SPI2. Мастер только, без прерываний, 9 бит, Clock phase = 0, Clock polarity = 0. Внутренний генератор HSE, частота процессора 80МГц(PLL), PA5 - на вывод для мигалки. Скорость SPI не важна.

Процессор STM32L476RG

Куб конфигурирует SPI выводы так:
//PB10 = SPI2_SCK = AF5
//PB12 = SPI2_NSS = AF5
//PC3 = SPI2_MOSI = AF5

Не могу выставить биты 2(MSTR: Master selection) и 6(SPE: SPI enable) - их сбрасывает проклятый MODF даже после первого обращения к SPI - записи в CR1.

Т.е. используя Куб и проект который он сгенерировал с использованием HAL, Вы пытаетесь организовать передачу данных игнорируя функции которые заложены для этого в HAL?
Димон Безпарольный
Цитата(Lagman @ May 15 2016, 00:03) *
Т.е. используя Куб и проект который он сгенерировал с использованием HAL, Вы пытаетесь организовать передачу данных игнорируя функции которые заложены для этого в HAL?

К черту куб и ХАЛ. С тех пор как я увидел что сгенертровал куб, я перестал доверять обоим. Буду вертеть регистрамт пока не пойму в чем дело. Куб генерит нерабочий код. В этом я уже убедился по UART. Написал все ручками с нуля и заработало.

В данном случае сгенерированный кубом код не работает также как и мой. Только нырять в дебри ХАЛА мне лень.

Кстати, те кто программирует камни не понимая что происходит внутри в корне неправы. Я таких программистов на работе спрашивал. Слово "регистр" приводит их в ужас. Толку от таких ноль. Только гонор и поучительный тон.
Димон Безпарольный
Я утверждал что Куб генерит нерабочий код. Вот он сгенерированный нерабочий код:






Т.е. видно что эти выводы должны быть сконфигурированы. А теперь смотрим конфигуратор выводов:

Код
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);

  /*Configure GPIO pin : PA5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}


Про SPI выводы ни строчки. Собственно у меня в этом Кубе и светодиод тоже не работает. Но разбираться почему в и так нерабочем коде - лень.
SPI програмный написал ручками. Работает идеально. Жаль что аппаратный SPI так и не удалось запустить. Может кто нибудь сгенерит мне в Кубе подобный код - буду благодарен. Мой вариант Куба - дерьмовый программист.

Кстати, почему в Full Duplex варианте вывод MISO называется Alternate Function Push Pull я так и не понял. Это же вход в конце концов.

В итоге средство, сделанное для сокращения времени программирования выполняет прямо противоположную функцию.

Еще бОльший маразм виден при детальном рассмотрении кода. Как известно, переключение входов на аналоговые рекомендуется для снижения потребления. Могучий Куб же для того, чтобы сконфигурировать ненужные мне выводы, включает тактирование всех GPIO:

Код
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

Щас прямо столько энергии сохранится, аж жуть!

А теперь взглянем на функцию, которая конфигурирует (т.е должна) GPIO и тактирование:

Код
    /* Init the low level hardware : GPIO, CLOCK, NVIC... */
    HAL_SPI_MspInit(hspi);


Вот она:
Код
__weak void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hspi);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_SPI_MspInit should be implemented in the user file
   */
}


Теперь понятно почему не работает SPI.
Lagman
CODE
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{

GPIO_InitTypeDef GPIO_InitStruct;
if(hspi->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */

/* USER CODE END SPI2_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();

/**SPI2 GPIO Configuration
PC3 ------> SPI2_MOSI
PB10 ------> SPI2_SCK
PB12 ------> SPI2_NSS
*/
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/* USER CODE BEGIN SPI2_MspInit 1 */

/* USER CODE END SPI2_MspInit 1 */
}

}
Димон Безпарольный
Заработало. Ну и каша!

Чтобы запрограммировать интерфейсные регистры CR I2C, например нужно выключить интерфейс. Чтобы запрограммировать интерфейсные регистры CR SPI нужно оказывается включить интерфейс!

Но в мануале об этом ни строчки не сказано.

Еще круче разработчики STM поступили с битом CS SPI интерфейса. Чтобы CS работал, нужно установить биты SSI, SSM, NSSP. Причем в разных регистрах. Но это еще не круто. Круто будет сейчас: от бита SSOE: SS output enable работа выхода CS не зависит! Хотя в мануале написано:

Цитата
Bit 2 SSOE: SS output enable
0: SS output is disabled in master mode and the SPI interface can work in multimaster
configuration
1: SS output is enabled in master mode and when the SPI interface is enabled. The SPI
interface cannot work in a multimaster environment.


С такой логикой недолго в Кащенко уехать. Я до сих пор не понимаю как мне удалось за пару дней таки запустить этот безумный интерфейс. На моей практике подобный эталон маразма помнится когда я связался с GSM интерфейсом. Отправка SMS в режиме PDU. Спецификация. Написать что - то подобное можно было если год принимать гашиш и ЛСД одновременно.
Димон Безпарольный
Вот некоторый опыт работы с Кубом:

Код
Куб в 90% генерит не рабочий код. Например для WatchDog куб как бы невзначай забыл про его разрешение: IWDG->KR = 0xCCCC; //Enable the IWDG

Для таймера - пищалки (пользуюсь при отладке) Куб забыл добавить это:
TIM3->CCMR2 = 3<<TIM_CCMR2_OC3FE; //OC3M[2:0] стр 917
TIM3->CCER = TIM_CCER_CC3E; //CC3E - разрешение работы capture/compare
TIM3->ARR = 0x97ff; //16 бит
TIM3->CCR3 = 0x96ff; //ARR > CCR3.

При инициализации SPI - DMA Куб забыл про это:
SPI2->CR1 |= SPI_CR1_SPE; //Bit 6 SPE: SPI enable
SPI2->CR2 |= SPI_CR2_TXDMAEN; //Bit 1 TXDMAEN: Tx buffer DMA enable Для DMA разрешить!!!

ADC: забыто это:
ADC1->CR |= ADC_CR_ADEN;     //Разрешить АЦП ADEN
ADC_CCR_CKMODE_0|    //Bits 17:16 CKMODE[1:0]: ADC clock mode
ADC1->IER |= ADC_IER_EOCIE;     //Разрешить прерывание по окончанию EOCIE(2) стр 505
NVIC->ISER[0] |= 1<<18;         //= 18, ADC12 global  Interrupt      
ADC1->CR |= ADC_CR_ADSTART;        //Начать преобразование ADSTART
x893
Как то сложно у вас всё.
И кубом и SPL и регистрами пользовался - ни разу с такими проблемами не сталкивался.
SMS PDU примерно час занял, надо было несохраняемые SMS отправлять.
Димон Безпарольный
Камешки наверно разные. Для одних все отлажено, для других не очень. Во всяком случае без добавления этих строк не работает периферия.

Удивил только CDC UART. Запустился сразу. Поставил драйвера - и работай. Плохо только что бутлоадер не нашел. Так SWD примочкой и пользуюсь. А в даташите красиво написано. Шить можно даже по I2C.

Ну и к слову - нахрена инженеры в SPI воткнули неотключаемый Fifo? Риторический вопрос. Передаю один байт - вываоивается 16 циклов. Подстроится можно, а если адрес надо 3-х битовый передать?

Криво как - то все...
Genadi Zawidowski
Цитата
Передаю один байт - вываоивается 16 циклов

Это не FIFO, это называется data packing feature, как "готовить" написано в reference manual.
зы: какое-то у Вас настроение воинственное...
romas2010
Ребят,при всем уважении к автору поста,но это все ерунда и просто нежелание включить мозг...UART вообще-то железобетонный интерфейс и во всех микроконтроллерах он практически одинаков...даже в каличном STM. Создайте проект с нуля и сами устанавливайте биты в регистрах, разберитесь с тактированием этого модуля,разберитесь,установив 57600,реально ли там такая скорость?
Димон Безпарольный
UART я давно уже оседлал. Проблем нет. Да, неправильно выразился - data packing. При 9 и более бит он не работает потому что не умещается в 16-битовое поле.

SPI у меня исправно работает с дисплеем Nokia 1100 через DMA. И я думал что его оседлал тоже. Но как только надо было поднять 8-битовые пересылки... data packing о!
AlexKLm
Цитата(MrYuran @ May 12 2016, 18:48) *
Вот интересно, какая связь между эклипсом и printf()

Я попробовал этот эклипс, потом он перестал работать, случилась у него авария - джава у него потерялась.
А printf() делается под конкретное железо и потому бессмысленно искать его (её) в готовом к употреблению виде.

Я сделал удобную мне функцию типа printf:
Код
#include <stdio.h>
#include <stdarg.h>

void LeF(char* format, ...)
{
  char szBuf[260];
  va_list argptr;
  va_start( argptr, format );
  vsnprintf( szBuf,260, format, argptr );
  va_end( argptr );
  HAL_UART_Transmit(&huart1, (uint8_t*)szBuf, strlen(szBuf), 100);
}

vsnprintf линкер нашёл где-то тут:
ibg_nano.a
libnosys.a


А вообще, я что хотел отметить:
Действительно, в мануалах нет данных о технике перехода вывода на AF и обратно в начальный вид.
Есть необходимость за-AF-еный вывод временно поиспользовать как обычный, но пока нет такой возможности
или вообще или с приемлемым размером кода. Вожусь с SPI1 уже пол дня.
jcxz
Цитата(AlexKLm @ Apr 11 2017, 12:10) *
vsnprintf линкер нашёл где-то тут:

Вместо всех sprintf-ов и snprintf-ов всегда использую:
extern "C" int _Printf( void *(*)(void *, int), void *, const char *, va_list *);
Она даёт на порядок больше возможностей. И собственно - это и есть базовая функция, которую вызывают все прочие библиотечные *printf-функции.
Имя дано для библиотеки IAR, но в других компиляторах думаю есть аналогичная.
SasaVitebsk
bb-offtopic.gif Судя по последним темам.
Раньше начинали с AVR или PIC. Теперь пришла вторая волна. Они начинают уже с Cortex-M0.
На глаз видны отличия в подходах и проблемы разные.
Раньше, всё же приходилось заглядывать в мануалы. И к чести Atmel можно сказать, что периферия была проста (как правило), даташиты лаконичны. Было много примеров. Можно было в одном примере посмотреть один модуль, в другом - другой и натягать проект. Ну а дальше уже кто как хотел. Если тяп-ляп, то так и оставить, а если кто вдумчивый, то переработать и получить приемлемый результат.
И что мы видим?
Появление HAL и, особенно куба, не убрало проблем, а нагородило их.
Неподготовленному программисту работать с ними достаточно тяжело. Да что говорить... И подготовленному непросто.
Кажущаяся простота подкупает, но, в результате, пользователь получает голимый 0. Сгенерированный проект, как правило не работает, и разборки идут не с камнем, а с кубом. Программист читает и ковыряет какую-то параллельную реальность. И абсолютно ничего не получает взамен. Ни знаний, ни опыта программирования, ни опыта работы с семейством, ни с камнем.
Ну уж лучше разбираться по примерам или библиотекам, как раньше. А то получишь только опыт работы борьбы с кубом.
SSerge
Цитата(jcxz @ Apr 11 2017, 17:54) *
Вместо всех sprintf-ов и snprintf-ов всегда использую:
extern "C" int _Printf( void *(*)(void *, int), void *, const char *, va_list *);
Она даёт на порядок больше возможностей. И собственно - это и есть базовая функция, которую вызывают все прочие библиотечные *printf-функции.
Имя дано для библиотеки IAR, но в других компиляторах думаю есть аналогичная.

А Вы в курсе, что в библиотеках IAR нет функции с таким именем? wink.gif
Откройте же EWARM_DevelopmentGuide.ENU.pdf, найдите где там написано про функцию __write и перестаньте закатывать солнце вручную.
jcxz
Цитата(SSerge @ Apr 11 2017, 16:23) *
А Вы в курсе, что в библиотеках IAR нет функции с таким именем? wink.gif
Откройте же EWARM_DevelopmentGuide.ENU.pdf, найдите где там написано про функцию __write и перестаньте закатывать солнце вручную.

Да ладно! А у меня компилит и глазом не моргнёт biggrin.gif
И при чём тут __write??? Она совсем о другом.
AlexKLm
Вот первый результат, когда удача улыбнулась:

__HAL_RCC_SPI1_CLK_DISABLE();

- только тогда удалось быстренько перескочить на ручное управление портом SPI1.
После этого:

HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5);

и сразу обычное для пина:

(в этом месте можно сразу уровень установить заранее при помощи HAL_GPIO_WritePin() )
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

теперь можно шевелить ногой SCK как обычно.

Обратный переход в режим SPI:

GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

__HAL_RCC_SPI1_CLK_ENABLE();

Это на скорую руку, дальнейшая проверка покажет, насколько это правильно.
Обращение к передаче/приёму во время переключения не допустимо,
иначе SPI перестаёт реагировать на управляющие команды.


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.