Что ж, после проверки моего кода и двойной проверки справочного руководства для моего микроконтроллера (RM0368 - справочное руководство для микроконтроллеров stm32f401xB / C / D / E), я понимаю и решаю проблему.Я уточню.
Прежде всего Я не выбрал источник системных часов и предположил, что это был HSI (высокоскоростные внутренние часы), и по какой-то причине это было не такэто был ВШЭ, то есть внешний высокоскоростной генератор.Поэтому я решил, что мне нужна функция синхронизации часов до , чтобы выбрать правильный источник синхронизации .
Во-вторых, я полностью забыл о предварительном масштабировании в APB1 (Advanced Peripheral Bus 1). Он делил частоту на 4 .Поэтому в функции инициализации часов я также настраиваю прескалер APB1 на известное значение, например, деленное на единицу.
/* Includes */
#include "stm32f4xx.h"
/* Private macro */
/* Private variables */
/* Private function prototypes */
void CLOCK_Init(void);
void UART2_Init(void);
void UART2_Test_TX(void);
/* Private functions */
/**
**===========================================================================
**
** Abstract: main program
**
**===========================================================================
*/
int main(void)
{
int i = 0;
/* Initialization */
CLOCK_Init();
UART2_Init();
/* Test */
UART2_Test_TX();
/* Infinite loop */
while (1)
{
i++;
}
}
Функция инициализации для часов устанавливает основной иAPB1 синхронизируется с известными значениями.Таким образом, позже конфигурация будет согласованной:
/* CLOCK_Init
* System clock source HSI
* APB1 prescaler 1
*
* Register affected: RCC_CFGR
*
*/
void CLOCK_Init(void)
{
RCC_TypeDef * pRCC;
pRCC = RCC;
RCC_ClocksTypeDef clocks;
uint32_t cpCFGR;
uint32_t mask;
//Setting HSI as system clock
cpCFGR = pRCC->CFGR;
// clear the SW1 SW0: Clock Source HSI
mask = ~((uint32_t)0b011);
cpCFGR &= mask;
pRCC->CFGR = cpCFGR;
// wait till SWS is 00, that is the clock source is HSI
while(1)
{
cpCFGR = pRCC->CFGR>>2;
if((~(cpCFGR) & (uint32_t)0b010) == (uint32_t)0b010) break;
}
/* Since the UART2 is connected to APB1 lets configure
* the prescaler in a known value, lets say 1
* */
//change the preescaler of APB1 from 4 to 1
cpCFGR = pRCC->CFGR;
mask = ~((uint32_t)0x00001C00); // RCC_CFGR_PPRE1
cpCFGR &= mask;
pRCC->CFGR = cpCFGR;
}
Инициализация USART2 конфигурирует его как UART с скоростью передачи 9600 бод, когда тактовая частота источника - HSI (16 МГц), а прескалер для APB1 установлен на 1Для получения дополнительной информации о значениях, пожалуйста, обратитесь к справочному руководству:
/*
* UART2_Init
* Asumming that the source clock is HSI and the APB1 prescaler is 1
*
* Register modified: RCC_APB1ENR,
* GIPIOA_MODER, GPIOA_AFR, GPIOA_PUPDR,
* USART2_CR1, USART2_BRR
*
*/
void UART2_Init(void)
{
RCC_TypeDef * pRCC;
pRCC = RCC;
GPIO_TypeDef * pGPIOA;
pGPIOA = GPIOA;
USART_TypeDef * pUSART2;
pUSART2 = USART2;
//1. Enable the peripheral clock
/*
* The USART2 is connected to the APB1 bus so we have to check here
* the Reset and Clock Configuration Enable register for APB1APB1_ENR
*
* */
pRCC->APB1ENR |= (1 << 17); // Set the USART2EN bit to enable the clock (RCC_APB1ENR_USART2EN)
//2. Configure the GPIO PINS related to UART TX and RX
/*
*
* To do this we need to find the alternate function of the pins in a reference table. That is located in the Section4, table 8 of the Data sheet:
* USART2_RX *PA3, PD6
* USART2_TX *PA2, PD5
* Also in the user manual of the board (UM1724) the RX and TX pins accessible from the PC are located in port A. We have a winner.
*
* That's good but not enough. PINs MAY HAVE UP TO 16 DIFFERENT FUNCTIONALITIES so we need another table and register to select it (in datasheet table 9)
*
* 2.1 So, enable the RCC clock for GPIOA AHB1
* 2.2 Configure the PINs as alternate function
* 2.3 Configure or not Internal Pull-up resistor
* 2.4 select the alternate function Table 9 of datasheet + GPIOA_AFRL, the low pins registers, from 0 to 7
*
* */
pRCC->AHB1ENR |= 1<<0;//RCC_AHB1ENR_GPIOAEN; // 2.1 Enable the source clock for GPIOA
// configuring pin 2 TX
pGPIOA->MODER &= ~(0b11<<4); // 2.2 Clear previous configuration in PIN2
pGPIOA->MODER |= (0b10<<4); // 2.2 Configure PIN2 as alternate function GPIO_Mode_AF
pGPIOA->AFR[0] &= ~(0b1111<<8); // 2.4 clear the bits in the register ;
pGPIOA->AFR[0] |= (0b0111 <<8); // 2.4 AF7 for TX pin
// FOR SPI, I2C, UART the lines must be held high. So we need pull_up resistors
pGPIOA->PUPDR &= ~(0b11<<4);
pGPIOA->PUPDR |= (0b01 <<4);
// configuring pin 3 RX (we are not really going to use this
pGPIOA->MODER &= ~(0b11<<6); // 2.2 Clear previous configuration in PIN3
pGPIOA->MODER |= (0b10<<6); // 2.2 Configure PIN3 as alternate function GPIO_Mode_AF
pGPIOA->AFR[0] &= ~(0b1111<<12); // 2.4 clear the bits in the register;
pGPIOA->AFR[0] |= (0b0111 <<12); // 2.4 AF7 for RX pin
// FOR SPI, I2C, UART the lines must be held high. So we need pull_up resistors
pGPIOA->PUPDR &= ~(0b11<<6);
pGPIOA->PUPDR |= (0b01 <<6);
// Note: I would be more efficient to configure all the pins at the same time but I did this way for clarity
//3. Configure the UART parameters: baudrate, data width, parity, number of stop bits etc
/*
* OVERSAMPLE 16
* Baudrate 9600
*
* OVER8 sampling divider
* 19.3.4 BaudRate = Fck/(16 * USARTDIV) .
* USARTDIV = DIV_Mantisa +(DIV_Fraction/ 8 x (2- OVER8))
* Fpclk = 16Mhz (default HSI)
*
* data width 8
* parity None
* stopbits 1
* */
// Configuring baudrate: 9600
pUSART2->CR1 &= ~(1<<15); // O: Oversample 16 OK1
pUSART2->BRR &= ~(0xFFFF); // Clear the mantisa and fraction
pUSART2->BRR |= (104<<4); // Mantisa
pUSART2->BRR |= (3<<0); // Fraction
/*
// configuring the baudrate deducting the system clock from the oscilloscope measurement, 13336000Hz
// The USARTDIV is 86.822916667: 86+13/16
pUSART2->BRR &= ~(0xFFFF); // Clear the mantisa and fraction
pUSART2->BRR |= (86<<4); // Mantisa
pUSART2->BRR |= (13<<0); // Fraction
uint32_t cBRR = pUSART2->BRR;
*/
pUSART2->CR1 &= ~(1<<12); // 8 bits OK1
pUSART2->CR1 &= ~(1<<10); // Parity control disable OK1
pUSART2->CR2 &= ~(0b11<<12); // 1 stop bits OK1
//4. Enable the TX engine of UART2 (do we need RX or we can save power?)
/*
* UE bit USART enable
* TE bit Transmit enable
* TDR Register to output the data
* */
pUSART2->CR1 |= (1<<3); // O: Transmit enable
//5. ENABLE THE USART peripheral Always at the end
/*
* Section 19.3.2
* USART_CR1.UE enable the usart
* USART_CR1.M number of bits 8,9
* USART_CR2 number of stops
* DMA enable...
*
* */
pUSART2->CR1 |= (1<<13); // O: USART enable
// Here is ready.
}
Функция тестирования такая же, но я включаю предложение old_timer для генерации квадратной последовательности импульсов на половину частотыиз последовательной передачи:
/* UART2_Test_TX
* Sends forever the character U to produce a square train of frec half baudrate
*/
void UART2_Test_TX(void)
{
USART_TypeDef * pUSART2;
pUSART2 = USART2;
char data[] = "U";
while(1)
{
while(!(pUSART2->SR && (1<<7)))// TXE transmit data register empty
{
__NOP();
}
// Feed the data register with data
pUSART2->DR = (uint16_t)data[0];
}
}
Я надеюсь, что это закрыть вопрос.Если кому-то нужны дальнейшие разъяснения, пожалуйста, спросите.
Я не анализировал происхождение конфигурации часов.Я предполагаю, что это связано с startup_stm32f40xx.s файл инициализации.