Полный пример; никакой другой код не нужен.
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, {r0, r1, r2, r4}
800000c: 08000017 stmdaeq r0, {r0, r1, r2, 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 на виртуальный диск, созданный при подключении карты.
Он навсегда загрузит 0123456701234567 на виртуальный COM-порт, созданный отладчиком на плате (115200 8N1).
Не то чтобы я использую rx, как показано, но вы, кажется, установили только один из двух.
Я не вижу, чтобы вы обнуляли биты регистра модера перед их установкой.
Математические расчеты в регистре скорости передачи данных выглядят неверно, если только вы не волшебным образом устанавливаете часы в другом месте, а затем запускаете этот код постфактум (а не при обычном включении / сбросе).
То же самое и с afrl; Сегодня я не смотрел регистр, но каждый раз, когда вы меняете биты (а не просто устанавливаете один бит на единицу), вам нужно обнулить другие биты в поле. В вашем случае 7 может быть всеми битами, поэтому может работать или равно, но проверьте это.
Я бы порекомендовал вам сделать это при записи в один регистр, а не с помощью волшебного изменчивого указателя & =, а затем на отдельном шаге | =. Вместо этого x = register; x & = .... x | = .... тогда register = x; Функция не меняет режим дважды, а только один раз. Зависит от функции и периферийного устройства, а также от того, как оно реагирует на записи относительно того, можно ли изменить дважды (возможно, в этом случае это нормально, общее правило).
Если вы делаете какую-то другую магию для часов, они также могут возиться с uart, неплохо просто сбросить его, в общем для такого периферийного устройства (возможно, даже было в документации, давно не просматривали). В противном случае вы не находитесь в известном состоянии (верно для всего в вашей программе, если вы предварительно запускаете что-то еще), и вы не можете просто коснуться нескольких полей в нескольких регистрах, вы должны коснуться всего периферийного устройства.
Я не думаю, что инициализация часов, указанная выше, требуется, я просто переключил ее на использование кварцевых часов, а не встроенных часов RC.
Редактировать
Очень извините, перечитываю ваш вопрос. Слева вверху как есть, хотя это не то, что вы просили, так что эта модификация делает так, что uart отправляется на PA9 с использованием UART1_TX.
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_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 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, данные не проходят через виртуальный com-порт, если вы хотите увидеть работу UART1.
Я изменил частоту с 16 МГц на 8 МГц, поэтому для 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 - это один из выводов заголовка, поэтому вы можете подключить к нему UART (3,3 В) и посмотреть, поступают ли ваши данные. Я бы порекомендовал вам просто попробовать 16000000/115200 = 138,8 = 0x8A или 0x8B в BRR, почему бы не всего за секунду.
В противном случае, если у вас есть прицел, поместите туда зонд. Я рекомендую вместо буквы K использовать U, который равен 0x55, что с 8N1, которое выглядит как прямоугольная волна, когда вы передаете так быстро, как можете (без пробелов между символами), и его действительно легко измерить с помощью осциллографа. затем поиграйте со своим регистром BRR и посмотрите, как это изменит частоту выходного сигнала осциллографа.
Это использует USART1_TX на PB6, и я удалил инициализацию кварцевых часов, поэтому он использует тактовую частоту HSI 16 МГц.
Принципиальная разница здесь в том, что у вас другая настройка 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(RCC_APB2ENR);
ra|=1<<4; //enable USART1
PUT32(RCC_APB2ENR,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);
ra=GET32(RCC_APB2RSTR);
ra|=1<<4; //reset USART1
PUT32(RCC_APB2RSTR,ra);
ra&=~(1<<4);
PUT32(RCC_APB2RSTR,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 на два вывода выше вывода PA9 на правой стороне платы D10 вместо D8, обратите внимание, что штыревые контакты справа находятся на полшага ниже штырьков заголовка Arduino, посмотрите документацию к плате, чтобы найти где подключить свой uart.
person
old_timer
schedule
22.08.2020