Giter Site home page Giter Site logo

cpq / bare-metal-programming-guide Goto Github PK

View Code? Open in Web Editor NEW
2.6K 2.6K 225.0 4.37 MB

A bare metal programming guide (ARM microcontrollers)

License: MIT License

Makefile 0.60% C 95.54% C++ 3.86%
arm baremetal cmsis embedded-web-server embedded-webserver ethernet gcc gpio irq make stm32 tutorial uart webserver

bare-metal-programming-guide's People

Contributors

boholmrasmussen avatar cpq avatar erusyd avatar mundahl avatar nideri avatar saracalihan avatar scaprile avatar ugurkebir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bare-metal-programming-guide's Issues

Make vector table read-only

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.

Efficiency improvement

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.

build problem for stm32f411re

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.
build error for 411re

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

suggested fix

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);

UART is not RS232

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!

Copying .data to RAM

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++;

Wrong KB size in Memory and Registers section?

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. :)

Question about SysTick

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?

Trouble flashing a Nucleo 144 with STM32L4R5

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};

Compilation fail on avr-gcc 12.2.2 MacOS

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!

Weird gpio_write issue: more than six calls do not work

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

gpio_error_blinky.zip

Webserver code not handling TP-Link loop detection

(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

Thank you

This repository is an absolute gem!

Thank you ❤️

No mention of `_sbrk` implementation in "Redirect printf() to UART" section

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.

Code example typo in section 8.4.1

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,

STM32 RAM address is consistently incorrect

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).

How to edit?

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

Setting SP using vector table

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

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.