cpq / bare-metal-programming-guide Goto Github PK
View Code? Open in Web Editor NEWA bare metal programming guide (ARM microcontrollers)
License: MIT License
A bare metal programming guide (ARM microcontrollers)
License: MIT License
Hi first of all thanks for this awesome guide.
I noticed what I think is a small typo in the code comment example.
In the readme.md: section 8.4.1
While setting port A3 to output mode.
the clearing is fine but then when setting only bit 6 to 1 the trailing comment is wrong.
This is the current code example:
* (volatile uint32_t *) (0x40020000 + 0) &= ~(3 << 6); // CLear bits 6-7
* (volatile uint32_t *) (0x40020000 + 0) |= 1 << 6; // Set bits 6-7 to 1
What I think it should be:
* (volatile uint32_t *) (0x40020000 + 0) &= ~(3 << 6); // Clear bits 6-7
* (volatile uint32_t *) (0x40020000 + 0) |= 1 << 6; // Set bit 6 to 1
Not major, but fixing it might clear some confusion for newcomers.
Thanks again,
Hello!
For step1 (the blinky LED), the code works as expected on my board (Nucleo-L4R5ZI-P), but I need to flash it twice in order to take action.
Any idea why would that be the case? Thank you!
I have also include a small change to my makefile:
flash: firmware.bin
st-flash erase
st-flash --reset write $< 0x8000000
Here is the output from my terminal when I flash it two times. I am inside VS Code.
PS C:\bare-metal-programming-guide-main\step-1-blinky> make flash
st-flash erase
st-flash 1.7.0
2022-12-29T13:10:25 INFO common.c: L4Rx: 640 KiB SRAM, 2048 KiB flash in at least 4 KiB pages.
Mass erasing
st-flash --reset write firmware.bin 0x8000000
st-flash 1.7.0
2022-12-29T13:10:25 INFO common.c: L4Rx: 640 KiB SRAM, 2048 KiB flash in at least 4 KiB pages.
file firmware.bin md5 checksum: 81de4b5e557657e7956c572abf64fba2, stlink checksum: 0x00004345
2022-12-29T13:10:25 INFO common.c: Attempting to write 648 (0x288) bytes to stm32 address: 134217728 (0x8000000)
EraseFlash - Page:0x0 Size:0x1000 2022-12-29T13:10:25 INFO common.c: Flash page at addr: 0x08000000 erased
2022-12-29T13:10:25 INFO common.c: Finished erasing 1 pages of 4096 (0x1000) bytes
2022-12-29T13:10:25 INFO common.c: Starting Flash write for F2/F4/F7/L4
2022-12-29T13:10:25 INFO flash_loader.c: Successfully loaded flash loader in sram
2022-12-29T13:10:25 INFO flash_loader.c: Clear DFSR
2022-12-29T13:10:25 INFO common.c: Starting verification of write complete
2022-12-29T13:10:25 INFO common.c: Flash written and verified! jolly good!
PS C:\bare-metal-programming-guide-main\step-1-blinky> make flash
st-flash erase
st-flash 1.7.0
2022-12-29T13:10:26 INFO common.c: L4Rx: 640 KiB SRAM, 2048 KiB flash in at least 4 KiB pages.
Mass erasing
st-flash --reset write firmware.bin 0x8000000
st-flash 1.7.0
2022-12-29T13:10:26 INFO common.c: L4Rx: 640 KiB SRAM, 2048 KiB flash in at least 4 KiB pages.
file firmware.bin md5 checksum: 81de4b5e557657e7956c572abf64fba2, stlink checksum: 0x00004345
2022-12-29T13:10:26 INFO common.c: Attempting to write 648 (0x288) bytes to stm32 address: 134217728 (0x8000000)
EraseFlash - Page:0x0 Size:0x1000 2022-12-29T13:10:26 INFO common.c: Flash page at addr: 0x08000000 erased
2022-12-29T13:10:26 INFO common.c: Finished erasing 1 pages of 4096 (0x1000) bytes
2022-12-29T13:10:26 INFO common.c: Starting Flash write for F2/F4/F7/L4
2022-12-29T13:10:26 INFO flash_loader.c: Successfully loaded flash loader in sram
2022-12-29T13:10:27 INFO flash_loader.c: Clear DFSR
2022-12-29T13:10:27 INFO common.c: Starting verification of write complete
2022-12-29T13:10:27 INFO common.c: Flash written and verified! jolly good!
Here is my main.c:
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include <inttypes.h>
#include <stdbool.h>
#define BIT(x) (1UL << (x)) // create a 32-bit number
#define PIN(bank, num) ((((bank) - 'A') << 8) | (num))
#define PINNO(pin) (pin & 255)
#define PINBANK(pin) (pin >> 8)
struct rcc {
volatile uint32_t CR, ICSCR, CFGR, PLLCFGR, PLLSAI1CFGR, PLLSAI2CFGR, CIER, CIFR,
CICR, RESERVE0, AHB1RSTR, AHB2RSTR, AHB3RSTR, RESERVE1, APB1RSTR1, APB1RSTR2, APB2RSTR, RESERVE2, AHB1ENR,
AHB2ENR, AHB3ENR, RESERVE3, APB1ENR1, APB1ENR2, APB2ENR, RESERVE4, AHB1SMENR, AHB2SMENR, AHB3SMENR, RESERVE5,
APB1SMENR1, APB1SMENR2, APB2SMENR, RESERVE6, CCIPR, BDCR, CSR, CRRCR, CCIPR2, RESERVE7, DLYCFGR;
};
#define RCC ((struct rcc *) 0x40021000)
struct gpio {
volatile uint32_t MODER, OTYPER, OSPEEDR, PUPDR, IDR, ODR, BSRR, LCKR, AFR[2], BRR;
};
#define GPIO(bank) ((struct gpio *) (0x48000000 + 0x400 * (bank)))
// Enum values are per datasheet: 0, 1, 2, 3
enum { GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_AF, GPIO_MODE_ANALOG };
static inline void gpio_set_mode(uint16_t pin, uint8_t mode) {
struct gpio *gpio = GPIO(PINBANK(pin)); // GPIO bank
int n = PINNO(pin); // Pin number
gpio->MODER &= ~(3U << (n * 2)); // Clear existing setting
gpio->MODER |= (mode & 3U) << (n * 2); // Set new mode
}
static inline void gpio_write(uint16_t pin, bool val) {
struct gpio *gpio = GPIO(PINBANK(pin));
gpio->BSRR |= (1U << PINNO(pin)) << (val ? 0 : 16);
}
static inline void spin(volatile uint32_t count) {
while (count--) asm("nop");
}
int main(void) {
uint16_t led = PIN('B', 7); // Blue LED
RCC->AHB2ENR |= BIT(PINBANK(led)); // Enable GPIO clock for LED
gpio_set_mode(led, GPIO_MODE_OUTPUT); // Set blue LED to output mode
for (;;) {
gpio_write(led, true);
spin(999999);
gpio_write(led, false);
spin(999999);
}
return 0;
}
// Startup code
__attribute__((naked, noreturn)) void _reset(void) {
// memset .bss to zero, and copy .data section to RAM region
extern long _sbss, _ebss, _sdata, _edata, _sidata;
for (long *src = &_sbss; src < &_ebss; src++) *src = 0;
for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++;
main(); // Call main()
for (;;) (void) 0; // Infinite loop in the case if main() returns
}
extern void _estack(void); // Defined in link.ld
// 16 standard and 91 STM32-specific handlers
__attribute__((section(".vectors"))) void (*tab[16 + 95])(void) = {_estack, _reset};
On my system, I could fix this error by exporting the TARGET as follows
export TARGET=firmware; make flash
is there any particular reason you doing:
asm("ldr sp, = _estack"); // Set initial stack pointer
rather than
__attribute__((section(".vectors"))) void (*tab[16 + 91])(void) = {
_estack, _reset
};
Vector zero should contain the initial stack pointer
Hi, I'm not able to build the example code for toolchain verification. Can you take a look? I'm on macos.
arm-none-eabi-gcc main.c -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion -Wformat-truncation -fno-common -Wconversion -g3 -Os -ffunction-sections -fdata-sections -I. -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -L/opt/homebrew/opt/[email protected]/lib -o firmware.elf
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-exit.o): in functionexit': exit.c:(.text.exit+0x14): undefined reference to
_exit'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /var/folders/j7/g10_rgn9119cdn3xz6ffp4l00000gn/T//cca2B4hB.o: in function_reset': /Users/linyz0100/Desktop/stm32playground/bare-metal-programming-guide/steps/step-0-minimal/main.c:16:(.text._reset+0x38): undefined reference to
_ebss'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Users/linyz0100/Desktop/stm32playground/bare-metal-programming-guide/steps/step-0-minimal/main.c:16:(.text._reset+0x3c): undefined reference to_sbss' /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Users/linyz0100/Desktop/stm32playground/bare-metal-programming-guide/steps/step-0-minimal/main.c:16:(.text._reset+0x44): undefined reference to
_sdata'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Users/linyz0100/Desktop/stm32playground/bare-metal-programming-guide/steps/step-0-minimal/main.c:16:(.text._reset+0x48): undefined reference to_sidata' /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /var/folders/j7/g10_rgn9119cdn3xz6ffp4l00000gn/T//cca2B4hB.o:/Users/linyz0100/Desktop/stm32playground/bare-metal-programming-guide/steps/step-0-minimal/main.c:22:(.vectors+0x0): undefined reference to
_estack'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-closer.o): in function_close_r': closer.c:(.text._close_r+0xc): undefined reference to
_close'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-lseekr.o): in function_lseek_r': lseekr.c:(.text._lseek_r+0x14): undefined reference to
_lseek'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-readr.o): in function_read_r': readr.c:(.text._read_r+0x14): undefined reference to
_read'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-sbrkr.o): in function_sbrk_r': sbrkr.c:(.text._sbrk_r+0xc): undefined reference to
_sbrk'
/Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/bin/ld: /Applications/ArmGNUToolchain/13.2.Rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/13.2.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-writer.o): in function_write_r': writer.c:(.text._write_r+0x14): undefined reference to
_write'
collect2: error: ld returned 1 exit status
make: *** [firmware.elf] Error 1
Hi!
I have Nucleo-64 stm32f411re and MikroelEktronica+ stm32f407zg boards,
adapting example code to f411re and f407zg worked perfectly with 2023 February version with manually added include directory and startup.c (modified obviously).
Current examples with SOURCES += cmsis_f4/Source/Templates/gcc/startup_stm32f411xe.s do not build
with errors:
in func. LoopFillZerobss in startup_stm32f411xe.s -- undefined reference to SysInit
in __libc_init_array.. -- undefined reference to _init
It seems that some path is now broken since startup_stm32f411xe.s and startup_stm32f429xx.s look very similar.
Also copying 200MB of files every time when new version of a project is created seems inefficient.
I copied cmsis_core and cmsis_f4 directories (dowdloaded by git clone..) to d:\gcc-arm\Work\ directory, but how to modify Makefile to access them is a mystery for me, pleaser help.
Best regards
dimitri1949
Should the following in startup code:
for (long *src = &_sdata, *dst = &_sidata; src < &_edata;) *src++ = *dst++;
be:
for (long *dst = &_sdata, *src = &_sidata; dst < &_edata;) *dst++ = *src++;
tools setup instructions for Linux(Ubuntu-20.04x) needs a small correction:
sudo apt -y install gcc-arm-none-eabi make stlink-tools (Instead of gcc-arm-embedded, use gcc-arm-none-eabi)
Following the instructions as listed and compiling with Arm GNU Toolchain 12.2.1 20230214 gives the following linker warning:
warning: firmware.elf has a LOAD segment with RWX permissions
because the .vectors
section is not READONLY
:
$ arm-none-eabi-objdump -h firmware.elf
firmware.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .vectors 0000026c 00000000 00000000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
1 .text 00000bd4 0000026c 0000026c 0000126c 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .rodata 00000024 00000e40 00000e40 00001e40 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
...
<SNIP>
This can be fixed with the following change to the startup code to make the vector table an array of constant function pointers:
-__attribute__((section(".vectors"))) void (*tab[16 + 139])(void) = {
+__attribute__((section(".vectors"))) void (*const tab[16 + 139])(void) = {
_estack, _reset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SysTick_Handler};
which causes the linker to mark the .vectors
section as READONLY
.
I meant to say ARM-gcc course :)
(base) admin@admins-Mac-mini step-0-minimal % make
arm-none-eabi-gcc main.c -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion -Wformat-truncation -fno-common -Wconversion -g3 -Os -ffunction-sections -fdata-sections -I. -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Tlink.ld -nostartfiles -nostdlib --specs nano.specs -lc -lgcc -Wl,--gc-sections -Wl,-Map=firmware.elf.map -o firmware.elf
/opt/local/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: cannot find -lc_nano: No such file or directory
collect2: error: ld returned 1 exit status
make: *** [firmware.elf] Error 1
Plz. advise, thanks!
Hi,
I'm trying to follow along with the guide for a STM32F3Discovery board. I wrote the GPIO/RCC API as in the instructions, making sure I used the correct register addresses for my MCU. The gpio_write function works fine when I turn on individual LEDs on the board, or even six of them together. However, as soon as I try calling gpio_write 7 times on seven different led pins, all the LEDs stop working. It seems like they come on for a split-second when I flash the firmware, but then go completely dark. Essentially,
This works:
// Specify some pins
uint16_t led1 = PIN('E',12);
uint16_t led2 = PIN('E',11);
uint16_t led3 = PIN('E',10);
uint16_t led4 = PIN('E',9);
uint16_t led5 = PIN('E',8);
uint16_t led6 = PIN('E',13);
// uint16_t led7 = PIN('E',14);
// uint16_t led8 = PIN('E',15);
RCC->AHBENR |= BIT(PINPERI(led1)+17); // PINPERI==PINBANK
gpio_set_mode(led1, GPIO_MODE_OUTPUT);
gpio_set_mode(led2, GPIO_MODE_OUTPUT);
gpio_set_mode(led3, GPIO_MODE_OUTPUT);
gpio_set_mode(led4, GPIO_MODE_OUTPUT);
gpio_set_mode(led5, GPIO_MODE_OUTPUT);
gpio_set_mode(led6, GPIO_MODE_OUTPUT);
// gpio_set_mode(led7, GPIO_MODE_OUTPUT);
// gpio_set_mode(led8, GPIO_MODE_OUTPUT);
gpio_write(led1, true);
gpio_write(led2, true);
gpio_write(led3, true);
gpio_write(led4, true);
gpio_write(led5, true);
gpio_write(led6, true);
// gpio_write(led7, true);
//gpio_write(led8, true);
This doesn't work:
// Specify some pins
uint16_t led1 = PIN('E',12);
uint16_t led2 = PIN('E',11);
uint16_t led3 = PIN('E',10);
uint16_t led4 = PIN('E',9);
uint16_t led5 = PIN('E',8);
uint16_t led6 = PIN('E',13);
uint16_t led7 = PIN('E',14);
// uint16_t led8 = PIN('E',15);
RCC->AHBENR |= BIT(PINPERI(led1)+17); // PINPERI==PINBANK
gpio_set_mode(led1, GPIO_MODE_OUTPUT);
gpio_set_mode(led2, GPIO_MODE_OUTPUT);
gpio_set_mode(led3, GPIO_MODE_OUTPUT);
gpio_set_mode(led4, GPIO_MODE_OUTPUT);
gpio_set_mode(led5, GPIO_MODE_OUTPUT);
gpio_set_mode(led6, GPIO_MODE_OUTPUT);
gpio_set_mode(led7, GPIO_MODE_OUTPUT);
// gpio_set_mode(led8, GPIO_MODE_OUTPUT);
gpio_write(led1, true);
gpio_write(led2, true);
gpio_write(led3, true);
gpio_write(led4, true);
gpio_write(led5, true);
gpio_write(led6, true);
gpio_write(led7, true);
//gpio_write(led8, true);
This issue also seems to be affecting the second part of the tutorial for me, where the spin function is used. In that case, even with one led, I get no blinking. I've attached my main.c, Makefile, and link.ld file with this issue.
Thanks for your help, and thanks for this great resource!
Bhaskar
It should not be said that MCUs (including the STM32) can transmit/receive data using RS232, which is an electrical specification as well as a communication protocol. You could damage the MCU if you try connecting it directly to RS-232 equipment.
Nice background read - thanks!
(UPDATE)
I turned off the "loop detect" option on the hub and the STM board connected and I was able to connect to the webserver.
I am not sure why this packets were seemingly disabling the process but was unable to connect and obtain an IP address until I disabled the loop detect.
I recently built the step-7 web server project and connected it to my home network. My hard wired network is running through a TP-Link vlan switch. I am running on a Nucleo F429-ZI board. The log messages below appear to indicate that the parser is not handling VLAN tagged frames (last line below) properly. This is not an area of expertise for me and I am wondering if there is a setting I need to tweak or some change in the code that i can make to get around this issue? I am new to this so please forgive me if this is not the proper method to ask a question.
Thank you
Rick Baker
1c914 3 mongoose.c:6904:tx_dhcp_discove DHCP discover sent
1c91a 3 mongoose.c:3474:mg_connect 350 0xffffffff udp://time.google.com:123
1c921 3 mongoose.c:3474:mg_connect 351 0xffffffff udp://8.8.8.8:53
1c927 3 mongoose.c:7406:mg_connect_reso 351 00000000:49268->08080808:53
1c92d 1 mongoose.c:404:mg_error 351 0xffffffff net down
1c933 1 mongoose.c:404:mg_error 351 0xffffffff DNS send
1c938 3 mongoose.c:3474:mg_connect 352 0xffffffff mqtt://broker.hivemq.com:1883
1c940 1 mongoose.c:404:mg_error 351 0xffffffff net down
1c945 1 mongoose.c:404:mg_error 351 0xffffffff DNS send
1c94b 1 mongoose.c:404:mg_error 352 0xffffffff net down
1c950 1 mongoose.c:404:mg_error 352 0xffffffff net down
1c956 1 mongoose.c:404:mg_error 352 0xffffffff net down
1c95b 1 mongoose.c:404:mg_error 352 0xffffffff net down
1c961 1 mongoose.c:404:mg_error 352 0xffffffff net down
1c967 3 mongoose.c:3451:mg_close_conn 352 0xffffffff closed
1c96c 1 mongoose.c:404:mg_error 350 0xffffffff DNS error
1c972 3 mongoose.c:3451:mg_close_conn 351 0xffffffff closed
1c977 3 mongoose.c:3451:mg_close_conn 350 0xffffffff closed
1c97c 3 mongoose.c:7278:mip_rx Unknown eth type 8899
printf
in newlib-nano makes a call to malloc
and thus requires _sbrk
to be implemented for it to work. I learned this the hard way when trying to complete the "Redirect printf() to UART" section on a TM4C123GH6PM
. Calls to printf
sent nothing but empty strings to the _write
syscall when _sbrk
was not implemented. _sbrk
is implemented in your linked solution at the end of the chapter; however, it would be helpful to mention in your explanation that both _write
and _sbrk
need to be implemented.
Apart from the first mention of the SRAM address, which correctly states 0x20000000 (and the linker script also has the correct value), the rest of the guide uses the incorrect 0x02000000 value, even including all the memory graphics, which put the SRAM before the flash address (also incorrect).
Hiho, and first of all thanks for that nice guide. I started following it and noticed the STM32F429 Datasheet has a different RAM size for the STM32F42xxx boards.
It says:
"The STM32F42xxx and STM32F43xxx feature 4 Kbytes of backup SRAM (see
Section 5.1.2: Battery backup domain) plus 256 Kbytes of system SRAM."
Maybe you just confused it with the section above that says:
"The STM32F405xx/07xx and STM32F415xx/17xx feature 4 Kbytes of backup SRAM (see
Section 5.1.2: Battery backup domain) plus 192 Kbytes of system SRAM."
Or maybe I just confused something, after all I am still learning and pretty new to this stuff. :)
In the following function:
static inline void gpio_write(uint16_t pin, bool val) {
struct gpio *gpio = GPIO(PINBANK(pin));
gpio->BSRR |= (1U << PINNO(pin)) << (val ? 0 : 16);
}
.. the BSRR |= .. will cause an unnecessary attempt to read the BSRR register, as BSRR is write-only. Replace |= with =.
Functionally it will be the same, only a tiny bit more efficient.
Thank you for a nice guide @cpq!
When reading it I came across some typos and similar simple edits ready for a pull request. How do you want them? In a pull request directly here or should I fork to my own profile first or just dump the edits here?
Regards,
Bo
This repository is an absolute gem!
Thank you ❤️
the last line of clock_init
while ((RCC->CFGR & 12) == 0) spin(1); // Wait until done
should probably be:
while ((RCC->CFGR & 12) != 8) spin(1);
I was looking at the code in the project's readme and saw this:
RCC->APB2ENR |= BIT(14);
I have some low level code in a simple test app for the STM32F407 Discovery board, that sets up SysTick but does nothing at all with the APB2ENR register, whereas your code sets the SYSCFGEN flag in that register. The odd thing is my SysTick works, runs fine.
Can you help me understand this difference?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.