2021-01-28 02:03 AM
I am working with the STM32F769 microcontroller and it's using FreeRTOS operating system. It uses the following clock configuration (216 MHz SystemCoreClock):
/** System Clock Configuration
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 432;
RCC_OscInitStruct.PLL.PLLQ = 9;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLR = 2; /* Even when DSI is disabled PLLR with 2 <= PLLR <= 7 according to RM0410 p.163 */
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Activate the Over-Drive mode
*/
if (HAL_PWREx_EnableOverDrive() != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
{
Error_Handler();
}
I have written a software transmit-only UART running at 3 MBaud on any arbitrary GPIO pin. For the most part it works great, but every once in a while, especially in interrupts, it starts "writing in Chinese" and strange characters appear in my terminal window. Does anybody know what's wrong?
#define IDLE_STATE 1
#define DISABLE_ALL_INTS_IF_NECESSARY() uint32_t old_primask; \
old_primask = __get_PRIMASK(); \
__disable_irq()
#define ENABLE_ALL_INTS_IF_THEY_WERE_ENABLED() if (!old_primask) \
{ \
__enable_irq(); \
}
static GPIO_TypeDef* TxPort_;
static uint16_t TxPin_;
void LL_UART_SW_TxOnly_enable(GPIO_TypeDef* TxPort, uint16_t TxPin) {
TxPort_ = TxPort;
TxPin_ = TxPin;
GPIO_InitTypeDef initStruct = {TxPin_, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_LOW, 0};
HAL_GPIO_Init(TxPort_, &initStruct);
SET_PIN(TxPort_, TxPin_, IDLE_STATE);
}
void LL_UART_SW_TxOnly_disable(void) {
GPIO_InitTypeDef initStruct = {TxPin_, GPIO_MODE_ANALOG, GPIO_NOPULL, GPIO_SPEED_LOW, 0};
HAL_GPIO_Init(TxPort_, &initStruct);
}
/* 216 MHz system clock */
#define OUTPUT_BIT(__BIT_NO__) *BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__]; \
*BSRR = BSRRvalues[__BIT_NO__];
inline static void __attribute__((optimize("O0"))) outputByte(volatile uint32_t* BSRR, uint32_t BSRRvalues[10]) {
OUTPUT_BIT(0);
OUTPUT_BIT(1);
OUTPUT_BIT(2);
OUTPUT_BIT(3);
OUTPUT_BIT(4);
OUTPUT_BIT(5);
OUTPUT_BIT(6);
OUTPUT_BIT(7);
OUTPUT_BIT(8);
*BSRR = BSRRvalues[9];
}
// Superfast (3 MBit/s) UART
void __attribute__((optimize("O3"))) LL_UART_SW_TxOnly_transmitByte(uint8_t byteToSend) {
uint32_t BSRRvalues[10];
BSRRvalues[0] = (IDLE_STATE == 1) ? (((uint32_t)TxPin_) << 16) : TxPin_; // Start bit
BSRRvalues[9] = (IDLE_STATE == 0) ? (((uint32_t)TxPin_) << 16) : TxPin_; // Stop bit
BSRRvalues[1] = BSRRvalues[(byteToSend & 0x01) ? 9 : 0]; // Bit 0
BSRRvalues[2] = BSRRvalues[(byteToSend & 0x02) ? 9 : 0]; // Bit 1
BSRRvalues[3] = BSRRvalues[(byteToSend & 0x04) ? 9 : 0]; // Bit 2
BSRRvalues[4] = BSRRvalues[(byteToSend & 0x08) ? 9 : 0]; // Bit 3
BSRRvalues[5] = BSRRvalues[(byteToSend & 0x10) ? 9 : 0]; // Bit 4
BSRRvalues[6] = BSRRvalues[(byteToSend & 0x20) ? 9 : 0]; // Bit 5
BSRRvalues[7] = BSRRvalues[(byteToSend & 0x40) ? 9 : 0]; // Bit 6
BSRRvalues[8] = BSRRvalues[(byteToSend & 0x80) ? 9 : 0]; // Bit 7
DISABLE_ALL_INTS_IF_NECESSARY();
outputByte(&TxPort_->BSRR, BSRRvalues);
ENABLE_ALL_INTS_IF_THEY_WERE_ENABLED();
}
void LL_UART_SW_TxOnly_transmitBuffer(uint8_t* pData, uint16_t numBytes) {
while (0 < numBytes--) {
LL_UART_SW_TxOnly_transmitByte(*pData++);
}
}
void LL_UART_SW_TxOnly_transmitNullTermString(const char* pData) {
while (*pData != 0) {
LL_UART_SW_TxOnly_transmitByte(*pData++);
}
}
2021-02-01 01:27 PM
Thanks! :)
Respect, no fear.
JW
2021-02-05 07:39 AM
I have now received faster USB-to-serial cables ( https://ftdichip.com/products/c232hd-ddhsp-0 ) and can confirm that it works great to run at 8 MBaud. I'm using very thin wires with no shielding and no impedance matching. I would like to thank everybody who contributed to this thread! Here's the final source code:
#define IDLE_STATE 1
#define DISABLE_ALL_INTS_IF_NECESSARY() uint32_t old_primask; \
old_primask = __get_PRIMASK(); \
__disable_irq()
#define ENABLE_ALL_INTS_IF_THEY_WERE_ENABLED() if (!old_primask) \
{ \
__enable_irq(); \
}
static GPIO_TypeDef* TxPort_;
static uint16_t TxPin_;
void LL_UART_SW_TxOnly_enable(GPIO_TypeDef* TxPort, uint16_t TxPin) {
TxPort_ = TxPort;
TxPin_ = TxPin;
GPIO_InitTypeDef initStruct = {TxPin_, GPIO_MODE_OUTPUT_PP, GPIO_NOPULL, GPIO_SPEED_LOW, 0};
SET_PIN(TxPort_, TxPin_, IDLE_STATE);
HAL_GPIO_Init(TxPort_, &initStruct);
}
void LL_UART_SW_TxOnly_disable(void) {
GPIO_InitTypeDef initStruct = {TxPin_, GPIO_MODE_ANALOG, GPIO_NOPULL, GPIO_SPEED_LOW, 0};
HAL_GPIO_Init(TxPort_, &initStruct);
}
/* 216 MHz system clock */
#define OUTPUT_BIT(__BIT_NO__) *BSRR = BSRRvalues[__BIT_NO__]; \
asm("DSB"); /* DSB is often used as a time-wasting instruction according to info on STM Forum */ \
asm("DSB"); /* DSB is often used as a time-wasting instruction according to info on STM Forum */ \
asm("DSB"); /* DSB is often used as a time-wasting instruction according to info on STM Forum */ \
asm("DSB") /* DSB is often used as a time-wasting instruction according to info on STM Forum */
inline static void __attribute__((optimize("O0"))) __RAM_FUNC outputByte(volatile uint32_t* BSRR, uint32_t BSRRvalues[10]) {
OUTPUT_BIT(0);
OUTPUT_BIT(1);
OUTPUT_BIT(2);
OUTPUT_BIT(3);
OUTPUT_BIT(4);
OUTPUT_BIT(5);
OUTPUT_BIT(6);
OUTPUT_BIT(7);
OUTPUT_BIT(8);
*BSRR = BSRRvalues[9];
}
// Super-duper-extra fast (8 MBit/s) UART
void __attribute__((optimize("O3"))) __RAM_FUNC LL_UART_SW_TxOnly_transmitByte(uint8_t byteToSend) {
uint32_t BSRRvalues[10];
BSRRvalues[0] = (IDLE_STATE == 1) ? (((uint32_t)TxPin_) << 16) : TxPin_; // Start bit
BSRRvalues[9] = (IDLE_STATE == 0) ? (((uint32_t)TxPin_) << 16) : TxPin_; // Stop bit
BSRRvalues[1] = BSRRvalues[(byteToSend & 0x01) ? 9 : 0]; // Bit 0
BSRRvalues[2] = BSRRvalues[(byteToSend & 0x02) ? 9 : 0]; // Bit 1
BSRRvalues[3] = BSRRvalues[(byteToSend & 0x04) ? 9 : 0]; // Bit 2
BSRRvalues[4] = BSRRvalues[(byteToSend & 0x08) ? 9 : 0]; // Bit 3
BSRRvalues[5] = BSRRvalues[(byteToSend & 0x10) ? 9 : 0]; // Bit 4
BSRRvalues[6] = BSRRvalues[(byteToSend & 0x20) ? 9 : 0]; // Bit 5
BSRRvalues[7] = BSRRvalues[(byteToSend & 0x40) ? 9 : 0]; // Bit 6
BSRRvalues[8] = BSRRvalues[(byteToSend & 0x80) ? 9 : 0]; // Bit 7
DISABLE_ALL_INTS_IF_NECESSARY();
outputByte(&TxPort_->BSRR, BSRRvalues);
ENABLE_ALL_INTS_IF_THEY_WERE_ENABLED();
}
void LL_UART_SW_TxOnly_transmitBuffer(uint8_t* pData, uint16_t numBytes) {
while (0 < numBytes--) {
LL_UART_SW_TxOnly_transmitByte(*pData++);
}
}
void LL_UART_SW_TxOnly_transmitNullTermString(const char* pData) {
while (*pData != 0) {
LL_UART_SW_TxOnly_transmitByte(*pData++);
}
}
void LL_UART_SW_TxOnly_transmitHexNumberAsASCII(uint32_t hexNum, uint8_t paddingTotalWidth) {
uint8_t ASCIIbuffer[8];
(void)convertNumberToHexASCIIstring(hexNum, ASCIIbuffer, sizeof(ASCIIbuffer));
LL_UART_SW_TxOnly_transmitBuffer(ASCIIbuffer + sizeof(ASCIIbuffer) - paddingTotalWidth, paddingTotalWidth);
}
void LL_UART_SW_TxOnly_transmitDecNumberAsASCII(int32_t decNum) {
uint8_t ASCIIbuffer[11];
int16_t startOffset = convertSignedNumberToDecASCIIstring(decNum, ASCIIbuffer, sizeof(ASCIIbuffer));
LL_UART_SW_TxOnly_transmitBuffer(ASCIIbuffer + startOffset, sizeof(ASCIIbuffer) - startOffset);
}
static uint8_t convertDigitToHexASCII(uint8_t digit) {
if (digit < 10) {
return (uint8_t) (digit + '0');
} else {
return (uint8_t) (digit + 'A' - 10);
}
}
int16_t convertNumberToHexASCIIstring(uint32_t numberToConvert, uint8_t* ASCIIbuffer, uint16_t ASCIIbufferSizeBytes) {
uint16_t i;
const uint32_t MAX_NUMBERS[] = {0, 0x10, 0x100, 0x1000, 0x10000, 0x100000, 0x1000000, 0x10000000};
if ((ASCIIbufferSizeBytes < 8) && (MAX_NUMBERS[ASCIIbufferSizeBytes] <= numberToConvert)) {
// The number to convert will not fit inside the provided buffer
return -32768;
}
for (i = 0; i < ASCIIbufferSizeBytes; i++) {
uint8_t digitToConvert = (uint8_t) ((numberToConvert >> (i << 2)) & 0x0000000F);
ASCIIbuffer[ASCIIbufferSizeBytes - i - 1] = convertDigitToHexASCII(digitToConvert);
}
for (i = 0; i < ASCIIbufferSizeBytes; i++) {
if (ASCIIbuffer[i] != '0') {
return i;
}
}
return ASCIIbufferSizeBytes - 1;
}
int16_t convertUnsignedNumberToDecASCIIstring(uint32_t numberToConvert, uint8_t* ASCIIbuffer, uint16_t ASCIIbufferSizeBytes) {
int16_t i;
const uint32_t MAX_NUMBERS[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
if ((ASCIIbufferSizeBytes < 10) && (MAX_NUMBERS[ASCIIbufferSizeBytes] <= numberToConvert)) {
// The number to convert will not fit inside the provided buffer
return -32768;
}
for (i = 0; i < ASCIIbufferSizeBytes; i++) {
uint32_t divisor = getPowerOfTen(ASCIIbufferSizeBytes - 1 - i);
uint32_t digitToConvert = numberToConvert / divisor;
ASCIIbuffer[i] = convertDigitToHexASCII(digitToConvert);
numberToConvert -= divisor * digitToConvert;
}
for (i = 0; i < ASCIIbufferSizeBytes; i++) {
if (ASCIIbuffer[i] != '0') {
return i;
}
}
return ASCIIbufferSizeBytes - 1;
}
int16_t convertSignedNumberToDecASCIIstring(int32_t numberToConvert, uint8_t* ASCIIbuffer, uint16_t ASCIIbufferSizeBytes) {
int16_t startIndex;
if (numberToConvert < 0) { // It's a negative number
startIndex = convertUnsignedNumberToDecASCIIstring((uint32_t)(0 - numberToConvert), ASCIIbuffer + 1, ASCIIbufferSizeBytes - 1);
if (0 <= startIndex) {
ASCIIbuffer[startIndex] = '-';
}
} else {
startIndex = convertUnsignedNumberToDecASCIIstring((uint32_t)numberToConvert, ASCIIbuffer, ASCIIbufferSizeBytes);
}
return startIndex;
}