LED not turning on on Nucleo-L031K6 with direct GPIO register access (bare-metal)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 12:04 PM - edited ‎2025-03-02 12:04 PM
I am trying to turn on the LD3 LED (connected to PB3) on the NUCLEO-L031K6 board using direct register access without libraries, but it is not working. The LED does not turn on. I have configured the pin control register, enabled the GPIOB clock, and set pin PB3 as output, but the LED still does not light up.
Here is the code I am using:
// NUCLEO-L031K6 #define PERIPH_BASE (0x40000000UL) #define AHB_OFFSET (0x00020000UL) #define AHB_BASE (PERIPH_BASE + AHB_OFFSET) #define IO_OFFSET (0x10000000UL) #define IOPORT_BASE (PERIPH_BASE + IO_OFFSET) #define GPIOB_OFFSET (0x0400UL) #define GPIOB_BASE (IOPORT_BASE + GPIOB_OFFSET) #define RCC_OFFSET (0x00021000UL) #define RCC_BASE (AHB_BASE + RCC_OFFSET) #define RCC_IOPENR_OFFSET (0x2CUL) #define RCC_IOPENR (*(volatile unsigned int *)(RCC_BASE + RCC_IOPENR_OFFSET)) #define GPIOPBEN (1U<<1) #define GPIOBMODER_OFFSET (0x00UL) #define GPIO_MODER (*(volatile unsigned int *)(GPIOB_BASE + GPIOBMODER_OFFSET)) #define GPIO_ODR_OFFSET (0x14UL) #define GPIO_ODR (*(volatile unsigned int *)(GPIOB_BASE + GPIO_ODR_OFFSET)) #define GPIOB_PIN3 (1U<<3) // LD3 user LED int main() { // Enable GPIOB clock RCC_IOPENR |= GPIOPBEN; // Set GPIOB pin 3 as output GPIO_MODER |= (1U<<6); GPIO_MODER &=~ (1U<<7); GPIO_ODR |= GPIOB_PIN3; // Turn on LED (set PB3 to HIGH) while (1) { } }
Details:
- Clock enabling: I am enabling the clock for GPIOB with RCC_IOPENR |= GPIOPBEN.
- Pin configuration as output: I am setting PB3 as output by modifying the MODER register (clearing and setting bits 6 and 7 of GPIOB_MODER).
- Turn on the LED: I am writing a 1 to the ODR register to set PB3 to HIGH and turn on the LED.
However, the LED is not turning on. Is there something I'm missing in the configuration?
What I've tried:
- I have tried with and without the code that sets GPIOB as output.
- I've also checked that there are no obvious hardware issues.
What else can I check or correct to turn on the LED on this board?
- Labels:
-
STM32L0 Series
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 1:15 PM - edited ‎2025-03-02 1:22 PM
First thing that catches my eye is in this code;
// Set GPIOB pin 3 as output
GPIO_MODER |= (1U<<6);
GPIO_MODER &=~ (1U<<7);
GPIO_ODR |= GPIOB_PIN3; // Turn on LED (set PB3 to HIGH)
while (1) {
}
First clear both bits then set the correct one.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 1:17 PM
1. Use ST-supplied headers to avoid looking for errors in your non-standard stuff.
2. Use debugger to single-step through your code and examine GPIOB registers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 1:30 PM
RCC offset to AHB area beginning is not 0x0002'1000 but 0x0000'1000.
Using the CMSIS-mandated device header - as @gbm suggested above - avoids this sort of errors.
JW
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 2:33 PM
I see as 0x0002'1000 in the reference manual
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 2:33 PM
I'm learning bare-metal without headers, that's my purpose of understanding everything from scratch
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 3:16 PM
No, you are learning bare metal with non-standard, non portable, incorrect headers inserted into .c source files. Not really a good idea.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 3:35 PM
No, 0x0002'1000 is offset to 0x4000'0000, not offset to AHB area beggining, which already has an offset of 0x0002'0000.
#define PERIPH_BASE (0x40000000UL) #define AHB_OFFSET (0x00020000UL) #define AHB_BASE (PERIPH_BASE + AHB_OFFSET) ------> AHB_BASE == 0x4002'0000
#define RCC_OFFSET (0x00021000UL) #define RCC_BASE (AHB_BASE + RCC_OFFSET) -----> RCC_BASE == 0x4004'1000, which is incorrect
JW
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-02 8:11 PM
Is translating addresses in the RM into pointers really helping you learn anything here? The learning comes with manipulating registers and understanding how they work, not with the addresses themselves. Use the standard CMSIS headers. You could have spent time learning instead of tracking down a typo here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2025-03-03 12:10 AM
I'm following a course, the first lessons are without headers, I won't be touching CMSIS until the next lessons.
I said learning from scratch. And to me from scratch means from scratch. Using an empty project without any headers or anything. That's what I understand from scratch, where you're using NOTHING BUT AN EMPTY PROJECT.
I don't know the reason right now as I'm completely new to this, but the course is structured like that for some reason, and I don't think I'm loosing time understanding how everything is build from A to Z. If I use someone else libraries, headers or any piece of code then I already skipped knowledge.
That's my opinion :)
