USART1没有为Nucleo F411RE提供任何腻子输出

问题描述

供应商:STM32 MC :Nucleo F411RE 相关链接:数据表,参考手册,Nucleo手册

问题:我正在使用STM32,ARM Cortex M4处理器学习嵌入式裸机。我已经用腻子正确配置了USART2。即使更改波特率,USART2的输出也可以正常工作。但是,我根本无法让USART1在Putty上传输任何内容

端口:GPIOB Pin :6 APB2时钟:84MHz 波特率:115200 ** USART1_BRR = 84MHz / 115200 = 729 [即0x02D9]

下面是我的时钟配置的屏幕截图:

enter image description here

这是我的代码

#include <stm32f4xx.h>

void USART1_Init(void);
void USART1_Write(int ch);
void delayMs(int delay);

int main(void)
{
    USART1_Init();
    while(1) {
        USART1_Write('K');
        delayMs(100);
    }
}

void USART1_Init(void)
{
    RCC->AHB1ENR |= 0x0002;
    RCC->APB2ENR |= 0x0010;

    GPIOB->MODER |= 0x2000;
    GPIOB->AFR[0] |= 0x7000000;

    USART1->BRR = 0x02D9;       // 115200 @84MHz
    USART1->CR1 = 0x0008;
    USART1->CR1 |= 0x2000;
}

void USART1_Write(int ch)
{
    while (!(USART1->SR & 0x0080)) {}
    USART1->DR = (ch & 0xFF);
}

void delayMs(int delay)
{
    int i;
    while (delay > 0) {
        for (i = 0; i < 3195; i++) {}
        --delay;
    }
}

我做什么: 我检查了所有配置是否都能正常打开。下面是RCC,GPIOB和USART1寄存器的屏幕截图:

enter image description here

enter image description here

enter image description here

首先,我尝试使用USART1认引脚(PA9和PA10)。但是然后,我在某处读到它们可能已配置用于USB输出。因此,我分别将PB6和PB7分别用于USART1 TX和RX。

我尝试更改波特率,打开DMAT(USART1->CR3),将GPIOB->OSPEEDR更改为高速,但还是一无所获。我在x86笔记本电脑上使用manjaro Linux。如果有帮助,我可以提供有关笔记本电脑配置的更多上下文。

我仍然怀疑我没有正确配置USART1->BRR,或者将USART1作为替代功能打开需要比现在更多的东西。

我仍然是嵌入式的初学者,我尝试了从框图和参考手册中可以推断出的一切。但是我似乎根本无法解决这个问题。为了使它起作用,我还需要对STM32上的USART1做更多的事情吗?

解决方法

一个完整的例子;不需要其他代码。

flash.s

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
    ldr r0,stacktop
    mov sp,r0
    bl notmain
    b hang
.thumb_func
hang:   b .

.align
stacktop: .word 0x20001000

.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr

.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr

.thumb_func
.globl dummy
dummy:
    bx lr

flash.ld

MEMORY
{
    rom : ORIGIN = 0x08000000,LENGTH = 0x1000
    ram : ORIGIN = 0x20000000,LENGTH = 0x1000
}
SECTIONS
{
    .text   : { *(.text*)   } > rom
    .rodata : { *(.rodata*) } > rom
    .bss    : { *(.bss*)    } > ram
}

notmain.c

void PUT32 ( unsigned int,unsigned int );
unsigned int GET32 ( unsigned int );

#define RCCBASE 0x40023800
#define RCC_CR          (RCCBASE+0x00)
#define RCC_CFGR        (RCCBASE+0x08)
#define RCC_APB1RSTR    (RCCBASE+0x20)
#define RCC_AHB1ENR     (RCCBASE+0x30)
#define RCC_APB1ENR     (RCCBASE+0x40)

#define GPIOABASE 0x40020000
#define GPIOA_MODER     (GPIOABASE+0x00)
#define GPIOA_AFRL      (GPIOABASE+0x20)

#define USART2BASE 0x40004400
#define USART2_SR       (USART2BASE+0x00)
#define USART2_DR       (USART2BASE+0x04)
#define USART2_BRR      (USART2BASE+0x08)
#define USART2_CR1      (USART2BASE+0x0C)

//PA2 is USART2_TX alternate function 1
//PA3 is USART2_RX alternate function 1

static int clock_init ( void )
{
    unsigned int ra;

    //switch to external clock.
    ra=GET32(RCC_CR);
    ra|=1<<16;
    PUT32(RCC_CR,ra);
    while(1) if(GET32(RCC_CR)&(1<<17)) break;
    ra=GET32(RCC_CFGR);
    ra&=~3;
    ra|=1;
    PUT32(RCC_CFGR,ra);
    while(1) if(((GET32(RCC_CFGR)>>2)&3)==1) break;

    return(0);
}
int uart2_init ( void )
{
    unsigned int ra;

    ra=GET32(RCC_AHB1ENR);
    ra|=1<<0; //enable port A
    PUT32(RCC_AHB1ENR,ra);

    ra=GET32(RCC_APB1ENR);
    ra|=1<<17; //enable USART2
    PUT32(RCC_APB1ENR,ra);

    ra=GET32(GPIOA_MODER);
    ra&=~(3<<4); //PA2
    ra&=~(3<<6); //PA3
    ra|=2<<4; //PA2
    ra|=2<<6; //PA3
    PUT32(GPIOA_MODER,ra);

    ra=GET32(GPIOA_AFRL);
    ra&=~(0xF<<8); //PA2
    ra&=~(0xF<<12); //PA3
    ra|=0x7<<8; //PA2
    ra|=0x7<<12; //PA3
    PUT32(GPIOA_AFRL,ra);

    ra=GET32(RCC_APB1RSTR);
    ra|=1<<17; //reset USART2
    PUT32(RCC_APB1RSTR,ra);
    ra&=~(1<<17);
    PUT32(RCC_APB1RSTR,ra);

    //8000000/(16*115200) = 4.34  4+5/16
    PUT32(USART2_BRR,0x45);
    PUT32(USART2_CR1,(1<<3)|(1<<2)|(1<<13));

    return(0);
}

void uart2_send ( unsigned int x )
{
    while(1) if(GET32(USART2_SR)&(1<<7)) break;
    PUT32(USART2_DR,x);
}

int notmain ( void )
{
    unsigned int rx;

    clock_init();
    uart2_init();
    for(rx=0;;rx++)
    {
        uart2_send(0x30+(rx&7));
    }
    return(0);
}

构建

arm-linux-gnueabi-as --warn --fatal-warnings -mcpu=cortex-m4 flash.s -o flash.o
arm-linux-gnueabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m4 -mthumb -c notmain.c -o notmain.o
arm-linux-gnueabi-ld -nostdlib -nostartfiles -T flash.ld flash.o notmain.o -o notmain.elf
arm-linux-gnueabi-objdump -D notmain.elf > notmain.list
arm-linux-gnueabi-objcopy -O binary notmain.elf notmain.bin

手臂-任何东西-都可以工作...

检查文件

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1,r0,r0
 8000004:   08000011    stmdaeq r0,{r0,r4}
 8000008:   08000017    stmdaeq r0,r1,r2,r4}
 800000c:   08000017    stmdaeq r0,r4}

08000010 <reset>:
 8000010:   f000 f86e   bl  80000f0 <notmain>
 8000014:   e7ff        b.n 8000016 <hang>

08000016 <hang>:
 8000016:   e7fe        b.n 8000016 <hang>

向量表看起来不错,有一半机会启动。

将notmain.bin复制到插入卡时创建的虚拟驱动器。

它将在板的调试器端(115200 8N1)创建的虚拟com端口上永久爆炸0123456701234567。

并不是说我正在使用rx,但是您似乎只设置了两者之一。

我看不到在设置调制解调器寄存器位之前将它们清零了。

除非您在其他地方神奇地设置了时钟,然后在事后运行此代码(而不是正常的上电/复位),否则数学运算在波特率寄存器上看起来是错误的。

同样适用于非洲;我今天没有看寄存器,但是每当您更改位(不仅将一位设置为1)时,都需要将字段中的其他位清零。在您的情况下,可能所有位都是7,所以可以等于或相等,但请检查一下。

我建议您在一次寄存器写入中执行此操作,而不是在魔术易失指针&=中进行操作,然后在单独的步骤| =中进行操作。取而代之的是x =寄存器; x&= .... x | = ....然后寄存器= x;该功能不会更改模式两次,而只会更改一次。取决于功能和外围设备及其对写入的反应,是否可以进行两次更改(在这种情况下,一般规则可能很好)。

如果您正在为时钟做其他魔术操作,则它们也可能与uart混为一谈,最好将其重置,通常对于这样的外围设备(可能甚至在文档中都没有看过,而)。否则,您就不会处于已知状态(如果您正在运行其他程序,那么该程序中的任何内容都是正确的),并且您不能简单地触摸几个寄存器中的几个字段,而必须触摸整个外围设备。

我认为不需要上面的时钟init,我只是将其切换为使用基于晶体的时钟,而不是片上RC时钟。

编辑

非常抱歉,重新阅读您的问题。即使不是您所要的,也请留在上面,以便进行此修改,以便uart使用UART1_TX在PA9上发送。

notmain.c

void PUT32 ( unsigned int,unsigned int );
unsigned int GET32 ( unsigned int );

#define RCCBASE 0x40023800
#define RCC_CR          (RCCBASE+0x00)
#define RCC_CFGR        (RCCBASE+0x08)
//#define RCC_APB1RSTR    (RCCBASE+0x20)
#define RCC_APB2RSTR    (RCCBASE+0x24)
#define RCC_AHB1ENR     (RCCBASE+0x30)
//#define RCC_APB1ENR     (RCCBASE+0x40)
#define RCC_APB2ENR     (RCCBASE+0x44)

#define GPIOABASE 0x40020000
#define GPIOA_MODER     (GPIOABASE+0x00)
//#define GPIOA_AFRL      (GPIOABASE+0x20)
#define GPIOA_AFRH      (GPIOABASE+0x24)

#define USART1BASE 0x40011000
#define USART1_SR       (USART1BASE+0x00)
#define USART1_DR       (USART1BASE+0x04)
#define USART1_BRR      (USART1BASE+0x08)
#define USART1_CR1      (USART1BASE+0x0C)

//PA9 is USART1_TX alternate function 7

static int clock_init ( void )
{
    unsigned int ra;

    //switch to external clock.
    ra=GET32(RCC_CR);
    ra|=1<<16;
    PUT32(RCC_CR,ra);
    while(1) if(((GET32(RCC_CFGR)>>2)&3)==1) break;

    return(0);
}
int uart_init ( void )
{
    unsigned int ra;

    ra=GET32(RCC_AHB1ENR);
    ra|=1<<0; //enable port A
    PUT32(RCC_AHB1ENR,ra);

    ra=GET32(RCC_APB2ENR);
    ra|=1<<4; //enable USART1
    PUT32(RCC_APB2ENR,ra);

    ra=GET32(GPIOA_MODER);
    ra&=~(3<<(9<<1)); //PA9
    ra|=  2<<(9<<1) ; //PA9
    PUT32(GPIOA_MODER,ra);

    ra=GET32(GPIOA_AFRH);
    ra&=~(0xF<<4); //PA9
    ra|=  0x7<<4; //PA9
    PUT32(GPIOA_AFRH,ra);

    ra=GET32(RCC_APB2RSTR);
    ra|=1<<4; //reset USART1
    PUT32(RCC_APB2RSTR,ra);
    ra&=~(1<<4);
    PUT32(RCC_APB2RSTR,ra);

    //8000000/(16*115200) = 4.34  4+5/16
    PUT32(USART1_BRR,0x45);
    PUT32(USART1_CR1,(1<<3)|(1<<2)|(1<<13));

    return(0);
}

void uart_send ( unsigned int x )
{
    while(1) if(GET32(USART1_SR)&(1<<7)) break;
    PUT32(USART1_DR,x);
}

int notmain ( void )
{
    unsigned int rx;

    clock_init();
    uart_init();
    for(rx=0;;rx++)
    {
        uart_send(0x30+(rx&7));
    }
    return(0);
}

PA9与外部插头引脚(Arduino样式的数据引脚)相连,很可能他们也不会将其用于USB。

这些引脚的MODER重置为零,因此等于或等于工作。

AFRL和AFRH重置为零,因此等于或相等将起作用。

要查看输出,您需要将uart设备连接到PA9,如果要查看UART1的工作,数据不会通过虚拟com端口。

我将时钟从16Mhz更改为8MHz,以便使用该芯片的uart(ST在其库中具有不同的外围设备,可以在制造芯片时进行选择)

    //8000000/(16*115200) = 4.34  4+5/16
    PUT32(USART1_BRR,0x45);

如果考虑一下,则8000000/115200 = 69.444 = 0x45。您无需单独进行分数数学运算。

因此,查看您的代码,您正在执行PB6,这对USART1_TX备用功能7来说很好。除了BRR之外,其他一切看起来都很好,并且您的延迟功能可能是无效代码并已优化,但由于您查找的是TX空状态在添加一个可以使您的代码正常工作的字符之前。

PB6是接头引脚之一,因此您可以将(3.3v)uart连接到它,并查看数据是否正在输出。我建议如果您只尝试在BRR中尝试16000000/115200 = 138.8 = 0x8A或0x8B,那为什么不花一秒钟呢?

否则,如果您有示波器,请在上面放一个探头。我建议不要使用字母K,而是使用0x55的U,它与8N1一起以方波的形式出现,当您尽可能快地传输时(字符之间没有间隙),并且真的很容易在示波器上测量。然后弄乱您的BRR寄存器,看看它如何改变示波器上的输出频率。

这在PB6上使用USART1_TX,我删除了晶体时钟初始化,因此它在使用16MHz HSI时钟。

根本上,这里的区别是您具有不同的BRR设置。

void PUT32 ( unsigned int,unsigned int );
unsigned int GET32 ( unsigned int );

#define RCCBASE 0x40023800
#define RCC_CR          (RCCBASE+0x00)
#define RCC_CFGR        (RCCBASE+0x08)
//#define RCC_APB1RSTR    (RCCBASE+0x20)
#define RCC_APB2RSTR    (RCCBASE+0x24)
#define RCC_AHB1ENR     (RCCBASE+0x30)
//#define RCC_APB1ENR     (RCCBASE+0x40)
#define RCC_APB2ENR     (RCCBASE+0x44)

#define GPIOBBASE 0x40020400
#define GPIOB_MODER     (GPIOBBASE+0x00)
#define GPIOB_AFRL      (GPIOBBASE+0x20)

#define USART1BASE 0x40011000
#define USART1_SR       (USART1BASE+0x00)
#define USART1_DR       (USART1BASE+0x04)
#define USART1_BRR      (USART1BASE+0x08)
#define USART1_CR1      (USART1BASE+0x0C)

int uart_init ( void )
{
    unsigned int ra;

    ra=GET32(RCC_AHB1ENR);
    ra|=1<<1; //enable port B
    PUT32(RCC_AHB1ENR,ra);

    ra=GET32(GPIOB_MODER);
    ra&=~(3<<(6<<1)); //PB6
    ra|=  2<<(6<<1) ; //PB6
    PUT32(GPIOB_MODER,ra);

    ra=GET32(GPIOB_AFRL);
    ra&=~(0xF<<24); //PB6
    ra|=  0x7<<24; //PB6
    PUT32(GPIOB_AFRL,ra);

    //16000000/115200
    PUT32(USART1_BRR,0x8B);
    PUT32(USART1_CR1,(1<<3)|(1<<13));

    return(0);
}

void uart_send ( unsigned int x )
{
    while(1) if(GET32(USART1_SR)&(1<<7)) break;
    PUT32(USART1_DR,x);
}

int notmain ( void )
{
    unsigned int rx;

    uart_init();
    for(rx=0;;rx++)
    {
        uart_send(0x30+(rx&7));
    }
    return(0);
}

还请注意,以这种速率爆炸时,根据数据模式,接收器可能会不同步,以致接收到的字符不是发送的字符,因此您可能需要按住重置按钮,板,然后松开并查看接收器是否能按照期望的方式看到图案,也许这就是为什么您要用K而不是U或其他东西来爆炸。

PB6引脚是板D10右侧的PA9引脚上方的两个引脚,而不是D8,请注意,右侧的公引脚比arduino母头引脚的引脚低半个台阶,请参阅有关文档。板上找到将uart连接起来的地方。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...