Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STN32F107 SYSCLK = 72 MHz
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
smk
Пытаюсь запустить отладку по USART. Как ни считаю USART1->BRR а все никак не могу получить нормальную передачу. Принимается совсем не то, передается. Раньне как-то на stm32f207 такой проблемы небыло. Что не так? Спасибо.
Код
void USART1_Init (void)
{
    unsigned int integerdivider, tmpreg, fractionaldivider;


    RCC->APB2ENR |= (1u<<2);
  /* Configure PA9 as alternate function push-pull */
    GPIOA->CRH &= ~(1u<<6);
    GPIOA->CRH |=(1u<<4)|(1u<<5)|(1u<<7);        
  /* Configure PA10 as input */
    GPIOA->CRL &= ~((1u<<8)|(1u<<9)|(1u<<11));
    GPIOA->CRL |=(1u<<10);        

  /* Determine the integer part */
  integerdivider = ((0x19 * fclk) / (0x04 * (115200)));
  tmpreg = (integerdivider / 0x64) << 0x04;
  /* Determine the fractional part */
  fractionaldivider = integerdivider - (0x64 * (tmpreg >> 0x04));
  tmpreg |= ((((fractionaldivider * 0x10) + 0x32) / 0x64)) & ((uint8_t)0x0F);
  /* Write to USART BRR */
// USARTx->BRR = (unsigned short)tmpreg;
    
    RCC->APB2ENR |= (1u<<14);
    USART1->BRR = (unsigned short)tmpreg;//313UL; //115200
    USART1->CR1 |= (1UL<<2)|(1UL<<3)|(1UL<<13);
}

void BYTE_Transmit_USART1 (unsigned char data)
{
    USART1->DR = data;
    while (!(USART1->SR & (1UL << 6)));
    USART1->SR &= ~(1UL << 6);    
}

//это передача.
for(i=0; i<10; i++)
{
BYTE_Transmit_USART1(0xAA);
}
Genadi Zawidowski
У меня (для stm32f1xx) вот так считается:

Код
    /* для устройств на шине APB2 (up to 72 MHz) */
    static uint_fast32_t
    calcdivround_apb2(
        int_fast32_t freq        /* требуемая частота на выходе делителя, в герцах. */
        )
    {
        return (APB2_FREQ + freq / 2) / freq;
    }

....

Код
    USART1->BRR = calcdivround_apb2(baudrate);        // младшие 4 бита - это дробная часть.

инициализация:

Код
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Включение тактирования USART1.


    USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE); // Transmitter Enable & Receiver Enables


    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;     //включить тактирование альтернативных функций

    arm_hardware_pioa_periphout_altfn2(GPIO_ODR_ODR9, 255);    // TX DATA line (2 MHz)
    arm_hardware_pioa_inputs(GPIO_ODR_ODR10);        // RX data line

    NVIC_EnableIRQ(USART1_IRQn);        // enable USART1_IRQHandler();

    USART1->CR1 |= USART_CR1_UE; // Включение USART1.
т.е., 4 дробных бита в делителе позволяют не учитывать oversampling на 16 в аппаратуре контроллера при расчёте скорости, а просто записатть результат деления тактовой частоты периферии на baud rate. Естественно, программирвоание делителя делать после включения этого периферийного устройства.

зы: BYTE_Transmit_USART1 сами придумали? Жестоко... Вы что, микропроцессор впервые в жизни увидели? Всегда делается просто - проверяется готовность, выводим байт. Бит готовности в этом регистре сбрасываается сам...

Да, мне ещё недавно встретился компилятор для ARM, который unsigned short считал 8-битным. Искренне надеюсь, что у вас не это поделие.
Ну и до кучи, в том компиляторе размер Int переключался в опциях проекта на 2/4 байта.
smk
Так я и делаю. Уже все перепробовал. Удивление необыкновенное. Должно работать но не работает. Т.е. работает, но baudrate какойто совсем не тот. А передача идет.
Aleksandr Baranov
Может такое вставить и посмотреть, чему равна apbclock?

Код
RCC_GetClocksFreq(&RCC_ClocksStatus);
  if ((*(u32*)&USARTx) == USART1_BASE)
  {
    apbclock = RCC_ClocksStatus.PCLK2_Frequency;
  }
  else
  {
    apbclock = RCC_ClocksStatus.PCLK1_Frequency;
  }

  /* Determine the integer part */
  integerdivider = ((0x19 * apbclock) / (0x04 * (USART_InitStruct->USART_BaudRate)));
  tmpreg = (integerdivider / 0x64) << 0x04;

  /* Determine the fractional part */
  fractionaldivider = integerdivider - (0x64 * (tmpreg >> 0x04));
  tmpreg |= ((((fractionaldivider * 0x10) + 0x32) / 0x64)) & ((u8)0x0F);

  /* Write to USART BRR */
  USARTx->BRR = (u16)tmpreg;
1113
Цитата(Aleksandr Baranov @ Nov 15 2013, 23:22) *
и посмотреть, чему равна apbclock?
может быть известная проблема - STM`мовские примеры рассчитаны на частоту кварца 25 МГц, а у вас какая?
Сергей Борщ
QUOTE (smk @ Nov 15 2013, 21:52) *
CODE
  /* Determine the integer part */
  integerdivider = ((0x19 * fclk) / (0x04 * (115200)));
  tmpreg = (integerdivider / 0x64) << 0x04;
  /* Determine the fractional part */
  fractionaldivider = integerdivider - (0x64 * (tmpreg >> 0x04));
  tmpreg |= ((((fractionaldivider * 0x10) + 0x32) / 0x64)) & ((uint8_t)0x0F);
  /* Write to USART BRR */
// USARTx->BRR = (unsigned short)tmpreg;
Серьезные расчеты.
CODE
    USART1->BRR = (PCLK1_FREQ + TERMINAL_BAUDRATE / 2) / TERMINAL_BAUDRATE;

smk
У меня выходит будто USART1->DR = 0xAA;//data; не выполняется. Одни нули на выходе.

Цитата(Сергей Борщ @ Nov 15 2013, 23:01) *
Серьезные расчеты.
Код
    USART1->BRR = (PCLK1_FREQ + TERMINAL_BAUDRATE / 2) / TERMINAL_BAUDRATE;

USART1->BRR = (72000000 + 115200 / 2) / 115200;

Цитата(1113 @ Nov 15 2013, 22:28) *
может быть известная проблема - STM`мовские примеры рассчитаны на частоту кварца 25 МГц, а у вас какая?

25 мгц

После однократной прокрутки нижеприведенного имею в терминале 40 нулевых байт.
Код
            for(i=0; i<10; i++)
                {
                    BYTE_Transmit_USART1(0xAA);
                }

            for(i=0; i<1000000; i++)
                {

                }
AHTOXA
У вас не включено тактирование альтернативных функций ног:
Код
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

(В примере от Genadi Zawidowski это есть)

ЗЫ. И ещё. Выкладывать в форуме код типа
Код
RCC->APB2ENR |= (1u<<14)

вместо
Код
RCC->APB2ENR |= RCC_APB2ENR_USART1EN

- это просто неуважение к участникам форума. Мало кто помнит наизусть, что такое 14й бит в APB2ENR. То есть, вы вынуждаете людей, которые хотят вам помочь, лезть в даташиты. Этим вы сильно снижаете вероятность того, что вам помогут.
(Да и вам потом самому свой код читать будет тяжело).
smk
Цитата(AHTOXA @ Nov 16 2013, 13:58) *
У вас не включено тактирование альтернативных функций ног:
Код
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

(В примере от Genadi Zawidowski это есть)


Не помогло. А на счет даташитов, то куда без них?
Genadi Zawidowski
Цитата
Не помогло

Приведите изменённый код здесь. Судя по тому, что принимаете на терминале все "0", выход к порту не подключился.
AHTOXA
Цитата(smk @ Nov 16 2013, 19:14) *
А на счет даташитов, то куда без них?

Неужели вы и правда не понимаете?
Когда я вижу строчку
RCC->APB2ENR |= (1u<<2);
, я без даташита не могу сказать, что включает эта строчка.
А если эта строчка будет выглядеть как
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
, то пойму сразу.
Вы же, когда постите сюда свой код, хотите, чтобы его проверили и поняли?
Думаете, многие полезли в даташит чтобы вам помочь?

Вот у вас ещё ошибка:
Код
  /* Configure PA10 as input */
    GPIOA->CRL &= ~((1u<<8)|(1u<<9)|(1u<<11));
    GPIOA->CRL |=(1u<<10);

биты для конфигурирования PA10 находятся в CRH.
smk
Цитата(AHTOXA @ Nov 16 2013, 16:40) *
Неужели вы и правда не понимаете?

Вот у вас ещё ошибка:
Код
  /* Configure PA10 as input */
    GPIOA->CRL &= ~((1u<<8)|(1u<<9)|(1u<<11));
    GPIOA->CRL |=(1u<<10);

биты для конфигурирования PA10 находятся в CRH.

Спасибо, действительно CRH. Надеюсь заработает. А на счет замечания, конечно так читабельнее. Но я уже натыкался на ошибочные дефайны и времени на то, чтоб это обнаружить уходило немало. Так что доверие подорвано. Единственное, это самому проверять перед тем как в код вставлять. Но как по мне так это лишние хлопоты когда даташит уже перед глазами. Впрочем для взгляда со стороны конечно Ваше предложение удобнее.
smk
Цитата(AHTOXA @ Nov 16 2013, 16:40) *
Вот у вас ещё ошибка:
Код
  /* Configure PA10 as input */
    GPIOA->CRL &= ~((1u<<8)|(1u<<9)|(1u<<11));
    GPIOA->CRL |=(1u<<10);

биты для конфигурирования PA10 находятся в CRH.

Не помогло.

А вот это что такое?
Код
arm_hardware_pioa_periphout_altfn2(GPIO_ODR_ODR9, 255);    // TX DATA line (2 MHz)
    arm_hardware_pioa_inputs(GPIO_ODR_ODR10);        // RX data line



Вот код, имеющийся в сухом остатке. Кто подскажет что не так?

Код
    RCC->APB2ENR |= (1u<<0);//AFIOEN: Alternate function I/O clock enable
    RCC->APB2ENR |= (1u<<2);//IOPAEN: I/O port A clock enable
    RCC->APB2ENR |= (1u<<14);//USART1EN: USART1 clock enable

    USART1->BRR = (72000000UL + 115200UL / 2UL) / 115200UL;
    USART1->SR &= ~(1UL << 6);    
    USART1->CR1 |= (1UL<<13);
    USART1->CR1 |= (1UL<<2)|(1UL<<3);//    
    
  /* Configure PA9 as alternate function push-pull */
    GPIOA->CRH &= ~((1u<<4)|(1u<<6));
    GPIOA->CRH |=(1u<<5)|(1u<<7);        
  /* Configure PA10 as input */
    GPIOA->CRH &= ~((1u<<8)|(1u<<9)|(1u<<11));
    GPIOA->CRH |=(1u<<10);            
}

void BYTE_Transmit_USART1 (unsigned char data)
{
    USART1->DR = 0xAA;//data;
    while (!(USART1->SR & (1UL << 6)));
}


Уже все перебрал, проверил. Все прописывется как надо и куда надо. Даташит перечитал. Не работает, но по всем меркам должно. Что может быть не так?
AHTOXA
Сначала настраиваем ноги,
потом настраиваем UART,
и только в самом конце включаем его.
(Биты считать не стал, уж не обессудьте).
smk
Цитата(AHTOXA @ Nov 18 2013, 19:38) *
Сначала настраиваем ноги,
потом настраиваем UART,
и только в самом конце включаем его.
(Биты считать не стал, уж не обессудьте).

По всякому уже делал. Кстати в даташите написано, что включение альтернативных функций ног без предварительно настроенной периферии не будет иметь эффекта. Конечно можно понять это так, что если не настроить периферию то и работать с ногами будет некому. Но поди знай наверняка что под этим имелось ввиду.
Genadi Zawidowski
Цитата
Вот код, имеющийся в сухом остатке. Кто подскажет что не так?

Вам уже советовали - замените магические числа на именованные константы. Я посчитал битики и нашёл ошибку, которой могло бы не быть, если Вы бы пользовались родными #define.
Цитата
А вот это что такое?

Код
arm_hardware_pioa_periphout_altfn2(GPIO_ODR_ODR9, 255);    // TX DATA line (2 MHz)
    arm_hardware_pioa_inputs(GPIO_ODR_ODR10);        // RX data line

Вот просто rocket sience... Как Вы вообще программированием занимаетесь? Ну не обращайте внимания на второстеепнные для понимания вещи... У Вас в программе есть аналогичный кусок, только он настроен на работу с двумя битами в PIOA, это универсальные функциии...
Если что, исходник лежит вот тут https://188.134.5.254/export/616/trunk/hardware.c - строка 2600 и 1320

И что за пляски со status register? Сделайте прямо:
Код
    while ((USART1->SR & USART_SR_TXE) == 0)
;
    USART1->DR = c;
smk
От безысходности подключил осциллограф. Установил скорость 9600. Реально получается примерно 1 мС/бит. Форма красивая. Передается то что нужно. Пробовал соединиться терминалом от винды. Тоже ничего не принимает. При этом контроллер шьется по ком-порту, а сам порт от компьютера нормально работает с модемом. Что бы это значило? Кстати на 9600 знакомые 4 нуля.
smk
Опытным путем удалось выяснить, что частота усарта лежит в пределах 7,5...8,5 МГц. Подставив в формулу 8 МГц получил устойчивую работу на 9600. От 0 до FF все передается без ошибок. Собственно почему 8 МГц? Системная 72 МГц, PCLK2 = 72 МГц если верить тому, что в регистрах. Может кто-то объяснить происходящее?
Golikov A.
ПЛЛ не настроился и вы на внутренний кварц свалились?
smk
Я житагом просматривал регистры, пошагово проходя все до main. Исходя из увиденного пересчитал все настройки. Получилось 72 МГц. Как теперь понимать ситуацию - даже не знаю. Стартап стандартный от кеил. Кварц 25 МГц.
Golikov A.
ну и что, на заборе тоже написано....
то что в регистрах задана частота 72, это не гарантия что ПЛЛ на нее настроился, что входной кварц той частоты как должен быть. Что вы переключили клок на ПЛЛ и прочее...

выведите на ножку системный клок, да померьте осциллографом, он же у вас есть...
smk
Осциллограф есть. Да, както нужно пройтись по этим вопросам и посмотреть что там на самом деле.
smk
Посмотрел ситуацию с тактированием. Получается так. Если идти пошагово до main, то с тактированием подядок. 72 МГц на усарте есть. Если же запускать "run to9 main" или просто с отключенным программатором, то на усарте 8 МГц. Т.е. тактирование не настраивается. В чем может быть дело? Раньше с подобным не сталкивался. Прочитать регистры ни программатором ни с помощью r = RCC->CFGR; не удается. Только если пошагово пройтись, то они видны. Помогите понять ситуацию. Спасибо.

Ну вобщем разобрался. Вот тут выходил по таймауту.
Код
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));


Если в строке увеличить значениетаймаута, то все в порядке.
Код
#define HSE_STARTUP_TIMEOUT   ((uint16_t)0xffff) /*0x0500!< Time out for HSE start up */


Хотелось бы знать почему HSE не выходит на готовность вовремя? Кейловцы же из чего-то исходили перед тем как записать значение 0х0500. Внесем ясность в это дело и тему можно закрывать.
OlegH
В системной библиотеке от ST, в модуле stm32f10x_rcc есть полезная в таких случаях функция
void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);
Которая позволяет получить реальные значения частот шин, которые имеются. Недавно она мне помогла определить наличие проблем с тактированием.

А что таймаута не хватает - кварц может медленно раскачиваться, либо плата плохо помыта
smk
Цитата(OlegH @ Nov 24 2013, 17:13) *
В системной библиотеке от ST, в модуле stm32f10x_rcc есть полезная в таких случаях функция
void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);
Которая позволяет получить реальные значения частот шин, которые имеются. Недавно она мне помогла определить наличие проблем с тактированием.

А что таймаута не хватает - кварц может медленно раскачиваться, либо плата плохо помыта

Надо посмотреть потом. Может действительно стоит того чтобы перепереть на нормальный язык.
HardEgor
Цитата(OlegH @ Nov 24 2013, 22:13) *
В системной библиотеке от ST, в модуле stm32f10x_rcc есть полезная в таких случаях функция
void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks);
Которая позволяет получить реальные значения частот шин, которые имеются. Недавно она мне помогла определить наличие проблем с тактированием.

Эта функция определяет не реальные частоты, а те которые получается из HSE_VALUE в stm32f10x.h и коэффициентов PLL, а если запустился HSI - тогда из него.
Но если HSE_VALUE правильно прописать, тогда baudrate будет корректно рассчитываться функцией USART_Init(......) из stm32f10x_usart.c когда либо HSE, либо HSI запустится.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.