You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Arduino Due USART0底层寄存器配置问题:无法收发数据求助

Arduino Due USART0(RX1/TX1)底层寄存器配置收发故障排查求助

尝试通过底层寄存器配置Arduino Due的USART0(映射至RX1和TX1)实现字符收发功能,已确认硬件连接无误且能正常控制内置LED,但USART0始终无法完成收发操作。已查阅Atmel官方文档但未发现配置遗漏,恳请提供排查建议。

完整配置代码如下:

#include <stdint.h>
#include "core_cm3.h"

/* Base addresses for peripherals */
#define PIOA_BASE (0x400E0E00U)
#define PMC_BASE  (0x400E0600U)

/* Peripheral instances */
#define PIOA ((PIO_TypeDef *)PIOA_BASE)
#define PMC  ((PMC_TypeDef *)PMC_BASE)

#define ID_PIOA     (11U)
#define ID_USART0   (17U) 

void USART0_Init(uint32_t baudrate) {
    // Step 1: Enable the peripheral clock for USART0
    PMC->PMC_WPMR = (0x504D43 << 8);
    PMC->PMC_PCER0 = (1 << ID_USART0); // Enable clock for USART0

    // Step 2: Configure TX and RX pins (PA10 for TX, PA11 for RX, Peripheral A)
    PIOA->PIO_WPMR = (0x50494F << 8);   // disable write protect

    PIOA->PIO_ABSR &= ~((1 <<10) | (1<<11)); // Select Peripheral A for USART0
    PIOA->PIO_PDR |= (1 <<10) | (1<<11);   // Disable GPIO control for PA10, PA11
    
    USART0->US_WPMR = (0x555341 << 8);  //disable write protect
    // Step 3: Disable USART0 before configuration
    USART0->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS;

    // Step 4: Configure baud rate
    uint32_t cd = SYSTEM_CLOCK / (16 * baudrate); // CD = MCK / (16 * baudrate)
    USART0->US_BRGR = cd;

    // Step 5: Configure USART0 mode
    USART0->US_MR = US_MR_CHRL_8_BIT    // 8-bit data
                  | US_MR_PAR_NO        // No parity
                  | US_MR_NBSTOP_1_BIT  // 1 stop bit
                  | US_MR_CHMODE_NORMAL; // Normal mode (not loopback or test)

    // Step 6: Enable the receiver and transmitter
    USART0->US_CR = US_CR_RXEN | US_CR_TXEN;
}

void USART0_SendChar(char c) {
    // Wait for the transmitter to be ready
    while (!(USART0->US_CSR & US_CSR_TXRDY));
    USART0->US_THR = c; // Write character to Transmit Holding Register
}

char USART0_ReceiveChar() {
    // Wait for a character to be received
    while (!(USART0->US_CSR & US_CSR_RXRDY));
    return USART0->US_RHR; // Read character from Receive Holding Register
}


int main(void) 
{
    PMC->PMC_WPMR = (0x504D43 << 8);
    // Enable the clock for PIOA
    PMC->PMC_PCER0 = (1 << ID_PIOA);
    // Enable clock for PIOB
    PMC->PMC_PCER0 = (1 << ID_PIOB);

    /* Set FWS according to SYS_BOARD_MCKR configuration */
    EFC0->EEFC_FMR = EEFC_FMR_FWS(4);
    EFC1->EEFC_FMR = EEFC_FMR_FWS(4);

    /* Initialize main oscillator */
    if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)) {
        PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE | SYS_BOARD_OSCOUNT | 
                                 CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
        while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) {
        }
    }

    /* Switch to 3-20MHz Xtal oscillator */
    PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE | SYS_BOARD_OSCOUNT | 
                               CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;

    while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) {
    }
    PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | 
                             PMC_MCKR_CSS_MAIN_CLK;
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
    }

    /* Initialize PLLA */
    PMC->CKGR_PLLAR = SYS_BOARD_PLLAR;
    while (!(PMC->PMC_SR & PMC_SR_LOCKA)) {
    }

    /* Switch to main clock */
    PMC->PMC_MCKR = (SYS_BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
    }

    /* Switch to PLLA */
    PMC->PMC_MCKR = SYS_BOARD_MCKR;
    while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
    }

    PMC->PMC_PCER0 = (1 << ID_PIOB);

    USART0_Init(9600);

    const char *message = "USART0 Initialized at 9600 baud.\r\n";
    for (const char *p = message; *p; p++) {
        USART0_SendChar(*p);
    }
    
    while (1) 
    {
        char received = USART0_ReceiveChar(); // Wait for a character
        USART0_SendChar(received);           // Echo it back
    }

    return 0;
}

排查建议

  • 补充USART0基地址与结构体定义:代码中直接使用USART0但未定义其基地址和对应结构体,编译器无法识别该外设。需添加:

    #define USART0_BASE (0x400E0800U)
    typedef struct {
      volatile uint32_t US_CR;     // Control Register
      volatile uint32_t US_MR;     // Mode Register
      volatile uint32_t US_IER;    // Interrupt Enable Register
      volatile uint32_t US_IDR;    // Interrupt Disable Register
      volatile uint32_t US_IMR;    // Interrupt Mask Register
      volatile uint32_t US_CSR;    // Channel Status Register
      volatile uint32_t US_RHR;    // Receive Holding Register
      volatile uint32_t US_THR;    // Transmit Holding Register
      volatile uint32_t US_BRGR;   // Baud Rate Generator Register
      volatile uint32_t US_RTOR;   // Receiver Time-out Register
      volatile uint32_t US_TTGR;   // Transmitter Timeguard Register
      volatile uint32_t US_WPMR;   // Write Protection Mode Register
      volatile uint32_t US_WPSR;   // Write Protection Status Register
      // 其他寄存器可根据需求补充
    } USART_TypeDef;
    #define USART0 ((USART_TypeDef *)USART0_BASE)
    
  • 定义SYSTEM_CLOCK宏:计算波特率时使用的SYSTEM_CLOCK未定义,需根据实际主时钟(MCK)值设置,Arduino Due默认MCK为84MHz,添加:

    #define SYSTEM_CLOCK 84000000U
    
  • 恢复外设写保护(规范操作):配置完PIOA、USART0、PMC后,建议恢复写保护防止误操作,例如配置PIOA后添加:

    PIOA->PIO_WPMR = 0; // 锁定写保护
    
  • 验证时钟配置正确性:确认main函数中最终MCK频率与SYSTEM_CLOCK一致,可通过读取PMC_MCKR寄存器或示波器测量相关引脚时钟验证。

  • 添加错误状态处理:在接收函数中增加错误检查与清除逻辑,避免因溢出、帧错误等导致接收阻塞:

    char USART0_ReceiveChar() {
        while (!(USART0->US_CSR & US_CSR_RXRDY)) {
            // 检查并清除错误状态
            if (USART0->US_CSR & (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE)) {
                USART0->US_CR = US_CR_RSTSTA;
            }
        }
        return USART0->US_RHR;
    }
    
  • 确认USART复位生效:在执行US_CR_RSTRX和US_CR_RSTTX后,可短暂延时或读取状态寄存器确保复位完成,再进行后续配置。

内容的提问来源于stack exchange,提问作者Godspped

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 05:17:03