PLL включается при отладке на STM32F767 Nucleo - PullRequest
1 голос
/ 11 января 2020

Последние 2 дня я ломал голову, пытаясь выяснить, что не так с моей очень простой программой UART в System Workbench для STM32 от STMicroelectronics. Почему-то, когда я установил:

USART3->BRR = (16000000/9600);  //Sets the baud rate to 9600 with a clock of 16MHz

Выход на последовательной линии - rubbi sh, однако, когда я нажимаю кнопку сброса на плате и запускаю ее, я вижу

Hello World

Как и ожидалось. В процессе копания я обнаружил, что источником системных часов является выход PLL (регистр RCC_CFGR), красная стрелка на изображении ниже:

RCC_CFGR

Биты Соответствующий красным стрелкам говорит мне, что PLL включен. Анализируя регистр RCC_PLLCFGR и вводя параметры PLLM, PLLN и PLLP вместе с соответствующими прескаллерами (AHB и APB1) в CubeMX I, я достиг тактовой частоты шины APB1 48 МГц. Итак, я сделал:

   USART3->BRR = (48000000/9600);   //Sets the baud rate to 9600 with a clock of 48MHz

И voilà делая шаг за шагом на отладчике, я вижу «HELLO WORLD», поэтому тактовая частота шины составляет 48 МГц. НО , и я нажимаю кнопку сброса и оставляю его включенным, теперь вывод не имеет смысла. Что-то в процессе отладки включает включение PLL и использование его в качестве источника SYSCLK.

Я скопировал и вставил код в Keil uVision, и не было никаких проблем, отладка и запуск, поэтому проблема не в сам код Я взглянул на startup_stm32.s, core_cm7.h и файлы отладки из SW4STM32 и не смог найти подсказки о том, почему это происходит. Глядя в справочное руководство Справочное руководство на стр. 170, значение сброса RCC_CFGR составляет 0x0000.0000, поэтому PLL выключается после сброса, поэтому что-то в отладке активно устанавливает PLL ON.

Я использую Tera Term, чтобы посмотреть на последовательный порт ST-LINK и Digital Discovery от Digilent, чтобы подтвердить, что происходит на шине, и оба дают мне четные данные.

Есть идеи?

Полный код:

#include "stm32f767xx.h"
#include "time.h"

/*
 * Function declarations
 */
void uS_Delay(int Time);
void mS_Delay(int Time);
void S_Delay(int Time);
void GPIOAa_Init(void);
void Config_TIM5(void);
void TIM5_IRQHandler(void);
void Enable_TIM5Interrupt(void);
void UART_Config(void);
void UART_Send(int character);

int Delay_End = 0;

int main(void)
{

    GPIOD_Init();

    Config_TIM5();

    Enable_TIM5Interrupt();

    UART_Config();


    int butao = 0;

    while(1)
    {
        UART_Send('H');
        mS_Delay(10);
        UART_Send('E');
        mS_Delay(10);
        UART_Send('L');
        mS_Delay(10);
        UART_Send('L');
        mS_Delay(10);
        UART_Send('O');
        mS_Delay(10);
        UART_Send(' ');
        mS_Delay(10);
        UART_Send('W');
        mS_Delay(10);
        UART_Send('O');
        mS_Delay(10);
        UART_Send('R');
        mS_Delay(10);
        UART_Send('L');
        mS_Delay(10);
        UART_Send('D');
        mS_Delay(10);


    }
}

/*
 * Functions
 */

void uS_Delay(int Time){

    uint32_t Delay = (uint32_t) (unsigned long) (Time*16);

/*  The APB bus cycle period is by default 62.5 nS, defined by the
 *  default bus frequency of 16 MHz. The number of steps to produce
 *  a 1 uS clock is:
 *
 *  Nº Steps = 1uS/62.5nS
 *  Nº Steps = 16
 *
 *  So for a delay of "Time" microseconds the number of steps is:
 *
 *  Delay = Time*16
*/

    TIM5->ARR = Delay;

/*  TIM-ARR value will be the counter boundary to roll over.
 *  The default bus frequency is 16MHz.
 */
    TIM5->CR1 |= 0x09;

/*  TIM5->CR1 is the main basic timer controller, in this situation
 *  the bits 0 and 3 are been set. Those bits enables the counting
 *  itself and the one-shot-mode, respectively. One-shot-mode makes
 *  it so when an update event occurs (overflow, underflow, etc) the
 *  counter stops counting, in other words the bit 0 of TIM%->CR1
 *  is cleared.
 */

    Delay_End = 0;

    while(Delay_End == 0);

    Delay_End = 0;

/*  Delay_End is a flag telling the uS_Delay() function that the
 *  specified delay hasn't finished (Delay_End = 0), so keeps the
 *  PC register stuck on (while(Delay_End == 0)). When the counter
 *  rolls over it generates an interrupt. The handler (TIM5_IRQHandler)
 *  sets this flag and now the program can get out of the while loop
 *  the flag is once again cleared (Delay_End = 0) and the program
 *  resumes.
 */
}

void mS_Delay(int Time){

    uint32_t Delay = (uint32_t) (unsigned long) (Time*16000);

/*  The APB bus cycle period is by default 62.5 nS, defined by the
 *  default bus frequency of 16 MHz. The number of steps to produce
 *  a 1 mS clock is:
 *
 *  Nº Steps = 1uS/62.5nS
 *  Nº Steps = 16.000
 *
 *  So for a delay of "Time" microseconds the number of steps is:
 *
 *  Delay = Time*16.000
*/

    TIM5->ARR = Delay;

/*  TIM-ARR value will be the counter boundary to roll over.
 *  The default bus frequency is 16MHz.
 */
    TIM5->CR1 |= 0x09;

/*  TIM5->CR1 is the main basic timer controller, is this situation
 *  the bits 0 and 3 are been set. Those bits enables the counting
 *  itself and the one-shot-mode, respectively. One-shot-mode makes
 *  it so when an update event occurs (overflow, underflow, etc) the
 *  counter stops counting, in other words the bit 0 of TIM%->CR1
 *  is cleared.
 */

    Delay_End = 0;

    while(Delay_End == 0);

    Delay_End = 0;

/*  Delay_End is a flag telling the uS_Delay() function that the
 *  specified delay hasn't finished (Delay_End = 0), so keeps the
 *  PC register stuck on (while(Delay_End == 0)). When the counter
 *  rolls over it generates an interrupt. The handler (TIM5_IRQHandler)
 *  sets this flag and now the program can get out of the while loop
 *  the flag is once again cleared (Delay_End = 0) and the program
 *  resumes.
 */
}

void S_Delay(int Time){

    uint32_t Delay = (uint32_t) (unsigned long) (Time*16000000);

/*  The APB bus cycle period is by default 62.5 nS, defined by the
 *  default bus frequency of 16 MHz. The number of steps to produce
 *  a 1 S clock is:
 *
 *  Nº Steps = 1S/62.5nS
 *  Nº Steps = 16.000.000
 *
 *  So for a delay of "Time" seconds the number of steps is:
 *
 *  Delay = Time*16.000.000
*/

    TIM5->ARR = Delay;

/*  TIM-ARR value will be the counter boundary to roll over.
 *  The default bus frequency is 16MHz.
 */
    TIM5->CR1 |= 0x09;

/*  TIM5->CR1 is the main basic timer controller, is this situation
 *  the bits 0 and 3 are been set. Those bits enables the counting
 *  itself and the one-shot-mode, respectively. One-shot-mode makes
 *  it so when an update event occurs (overflow, underflow, etc) the
 *  counter stops counting, in other words the bit 0 of TIM%->CR1
 *  is cleared.
 */

    Delay_End = 0;

    while(Delay_End == 0);

    Delay_End = 0;

/*  Delay_End is a flag telling the uS_Delay() function that the
 *  specified delay hasn't finished (Delay_End = 0), so keeps the
 *  PC register stuck on (while(Delay_End == 0)). When the counter
 *  rolls over it generates an interrupt. The handler (TIM5_IRQHandler)
 *  sets this flag and now the program can get out of the while loop
 *  the flag is once again cleared (Delay_End = 0) and the program
 *  resumes.
 */
}

void GPIOD_Init(void){
    int a;

    RCC->AHB1ENR    |= 0x08;            //Enables clock for port D

    a = RCC->AHB1ENR;                   //Small delay

    GPIOD->MODER    |= 0x00020000;
/*
 * Sets output mode for alternate mode for pin PD8
 */

    GPIOD->AFR[1]   |= 0x00000007;
/*
 * Alternate function 7 selected for pin PD8
 */
}

void Config_TIM5(void){
    int a;

    RCC->APB1ENR |= 0x08;           //Enables clock for TIM5

    a = RCC->APB1ENR;               //Small delay

    TIM5->DIER |= 0X01;             //Enables update interrupt
}

void TIM5_IRQHandler(void){

    Delay_End = 1;                  //The specified delay time has ended

    TIM5->SR &= ~(0x01);            //Clears the update event flag
}

void Enable_TIM5Interrupt(void){

    NVIC->ISER[1] = 0x40000;        //Enables interrupt event from TIM5 peripheral

    NVIC->IP[50] = 0x00;            //Sets the priority for the TIM5 interrupt
}

void UART_Config(void){
    int a;

    RCC->APB1ENR |= 0x00040000;     //Enable clock for UART4

    a = RCC->APB1ENR;               //Small delay

    USART3->CR1 |= 0x08;                //Enable the transmitter

    USART3->BRR = (48000000/9600);  //Sets the baud rate to 9600

    USART3->CR1 |= 0x01;                //Enable the USART4

}

void UART_Send(int character){
    USART3->TDR = (character);
}

Edit1: я запутался с RCC_CR и RCC_CFGR, но проблема та же.

Edit2: я заметил что prescalers для шин APB1 и APB2 также были изменены.

Edit3: Обходное решение при запуске сеанса отладки нажмите значок (Сброс чипа и перезапуск сеанса отладки ), эта кнопка перезапустит сеанс отладки со сбросом. Таким образом, содержимое регистров соответствует ожиданиям. Я все еще нахожусь в поиске постоянного решения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...