cancel
Showing results for 
Search instead for 
Did you mean: 

Need help to understand relationship of USART1 (as a source of interrupts), EXTI (as an enabler of external interrupts), and NVIC. USART1 RXNE=1 with RXNEIE=1 does not cause interrupt.

wb0gaz
Senior

(BACKGROUND) I'm working on small (GCC/C-language) tests of STM32F051 with STM32CubeIde 1.8.0 on STM32F051 target. These tests are being done ---> without HAL, Lower Level drivers, but am using #include "cmsis_gcc.h" to access CPU interrupt enable/disable/status <---, so your patience is appreciated (that is, I don't intend in these tests to involve HAL or Lower Level drivers). RM0091 is my documentation resource.

(PROBLEM) USART1 is configured to cause interrupt (RXNEIE=1) when RXNE=1 (receive character). Settings verified (RXNE becomes 1 when a receive character is accepted, and RXNEIE is 1.) The expected entry to void USART1_IRQHandler(void) is not happening.

(QUESTIONS)

1. Section 11.2.5: "EXTI line 25 is connected to the internal USART1 wakeup event". Is this used to allow USART1 interrupt request to reach the CPU? I am not using sleep or wake up conditions (the CPU is always running.) In this case is "event" same as "interrupt"?

2. RM0091 section 11.2.4 includes an instruction I do not understand: "• Configure the enable and mask bits that control the NVIC IRQ channel mapped to the EXTI so that an interrupt coming from one of the EXTI line can be correctly acknowledged." From what I see in the various examples at the end of RM0091 (however, not in the USART examples in section A.19.12), two important steps are:

NVIC_EnableIRQ();

NVIC_SetPriority();

I do not see any definition of NVIC registers in RM0091. cmsis_gcc.h contains nothing referring to NVIC. I have no other libraries or include files referenced at this point. Is NVIC something I can manipulate with registers like other peripherals?

I believe __enable_irq() is working: __get_PRIMASK() result follows the expected result based on preceding __disable_irq() or __enable_irq().

Thank you for any suggestions, questions or requests for clarifying information.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

You may have better luck by generating a project with CubeMX, then deleting everything HAL-related. There isn't much. This will give you a starting point that includes the appropriate CMSIS headers and basic startup functionality.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

13 REPLIES 13

> Section 11.2.5: "EXTI line 25 is connected to the internal USART1 wakeup event". Is this used to allow USART1 interrupt request to reach the CPU?

No, that's not the "common" USART1 interrupt, it's a different signal from USART1 (for details, see Wakeup from Stop mode using USART subchapter of USART). You don't need to be bothered by that at this moment.

> two important steps are:

> NVIC_EnableIRQ();

> NVIC_SetPriority();

NVIC_SetPriority(); is not that important, but - in your case - NVIC_EnableIRQ(USART1_IRQn); is.

> I do not see any definition of NVIC registers in RM0091.

Because they are part of the processor, i.e. documented in PM0215 (and related ARM documents).

On the documentation here, some interrupt debugging hints here.

JW

The NVIC is part of the Cortex-Mx, its not part of ST's IP and isn't in the RM, it will be in the PM (Programming Manual), or one of ARM's TRM (Technical Reference Manual)

Also good coverage in books by Joseph Yiu, Essential Cortex whatever..

The EXTI is an external pin mapping interrupt device, it also connects a number of internal nodes, which typically function when the core/peripherals are shutdown. ie your UART case, the UART isn't functional in the larger sense, but has the ability to trigger/start up the core. See also wakeup pins, or RTC alarms, etc. The EXTI is also a way of hiding a lot of interrupt sources, spanning a lot of peripherals, where as peripheral tend to have one or two of their own interrupt vectors, but with multiple internal sources specific to the peripheral, ie TXE, RXNE, TC, IDLE, etc. And one service routine can manager all the sub-sources.

Events/Interrupts, yes subtly different. Can't say I got much helpful to say, as I recall an event can have longer duration, initiating other things, whereas the interrupt does its thing, exits and the MCU can go back to sleep.

Interrupts are not re-entrant, you have to leave for the NVIC/MCU internal state to unwind, it can tail-chain back in immediately, but it won't interrupt itself, and it won't let lower priority (higher number) ones interrupt either, ones with higher preemption can push a new interrupt context.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
wb0gaz
Senior

Thank you both - it is helpful. I am not new to interrupts and microcontrollers, but I am VERY new to STM32 and ARM (cold start beginning 2 weeks ago of part-time effort.)

I appreciate your offers to help guide! The boundary between STM32 and ARM inside the MCU is new experience, it explains why it seems "not everything is in one place".

Now, I believe I am creating STM32CubeIDE wrong for my project goal ("bare metal", no HAL, no lower level support, just "bare metal"), because I think I should be able compile __enable_irq() and NVIC_EnableIRQ(USART1_IRQn) (for example), without searching for .h files and experiencing failed dependencies (I could not compile NVIC_EnableIRQ(USART1_IRQn) this way so I think better to start again fresh.

I have saved the source code from my small experiment, and I now created new project in STM32CubeIDE specifically to verify ability to compile __enable_irq(), etc., and also NVIC_EnableIRQ(). Until I can solve that problem, I cannot proceed.

File > New > STM32 Project > Part number (STM32F051C8), select LQFP48 package > Next > Name "nvictest", [x] Use default location, Targeted language C, Targeted binary type Executable, Targeted Project type Empty > Finish

My project now contains main.c (copy below), I added only __enable_irq() for test.

It cannot compile __enable_irq() (errors below), and I do not think could compile NVIC_EnableIRQ(USART1_IRQn). It does not contain Drivers\ folder, which I think is where the important support files for NVIC_EnableIRQ(USART1_IRQn) and __enable_irq() can be found.

(main.c for trivial example project)

#include <stdint.h>
 
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif
 
int main(void)
{
	__enable_irq();
    /* Loop forever */
	for(;;);
}

(compiler error result)

15:54:09 **** Build of configuration Debug for project nvictest ****
 
make -j4 all 
 
arm-none-eabi-gcc -mcpu=cortex-m0 -g3 -DDEBUG -c -x assembler-with-cpp -MMD -MP -MF"Startup/startup_stm32f051c8tx.d" -MT"Startup/startup_stm32f051c8tx.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Startup/startup_stm32f051c8tx.o" "../Startup/startup_stm32f051c8tx.s"
 
arm-none-eabi-gcc "../Src/main.c" -mcpu=cortex-m0 -std=gnu11 -g3 -DDEBUG -DSTM32 -DSTM32F051C8Tx -DSTM32F0 -c -I../Inc -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Src/main.d" -MT"Src/main.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Src/main.o"
 
arm-none-eabi-gcc "../Src/syscalls.c" -mcpu=cortex-m0 -std=gnu11 -g3 -DDEBUG -DSTM32 -DSTM32F051C8Tx -DSTM32F0 -c -I../Inc -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Src/syscalls.d" -MT"Src/syscalls.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Src/syscalls.o"
 
arm-none-eabi-gcc "../Src/sysmem.c" -mcpu=cortex-m0 -std=gnu11 -g3 -DDEBUG -DSTM32 -DSTM32F051C8Tx -DSTM32F0 -c -I../Inc -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Src/sysmem.d" -MT"Src/sysmem.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Src/sysmem.o"
 
../Src/main.c: In function 'main':
../Src/main.c:28:2: warning: implicit declaration of function '__enable_irq' [-Wimplicit-function-declaration]
  28 | __enable_irq();
     | ^~~~~~~~~~~~
arm-none-eabi-gcc -o "nvictest.elf" @"objects.list"  -mcpu=cortex-m0 -T"C:\Users\user\Desktop\stm32\nvictest\STM32F051C8TX_FLASH.ld" --specs=nosys.specs -Wl,-Map="nvictest.map" -Wl,--gc-sections -static --specs=nano.specs -mfloat-abi=soft -mthumb -Wl,--start-group -lc -lm -Wl,--end-group
 
c:\st\stm32cubeide_1.8.0\stm32cubeide\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.9-2020-q2-update.win32_2.0.0.202105311346\tools\arm-none-eabi\bin\ld.exe: ./Src/main.o: in function `main':
 
C:/Users/user/Desktop/stm32/nvictest/Debug/../Src/main.c:28: undefined reference to `__enable_irq'
 
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:63: nvictest.elf] Error 1
"make -j4 all" terminated with exit code 2. Build might be incomplete.
15:54:10 Build Failed. 3 errors, 1 warnings. (took 843ms)
 
 

###

This is current condition.

Thank you again,

Dave

I don't use CubeIDE so can't give specific help for that.

The intended usage is of CMSIS headers is, that you #include "stm32f0xx.h" which automatically #includes the appropriate specific device header (based on the define passed usually through command-line (you have -DSTM32F051C8Tx but that does not look OK to me, I'd expect -DSTM32F051x8) and also the whole chain of CMSIS headers. This assumes path to those headers is passed to compiler, too, through -I (or the headers are simply in the directory where the compilation happens).

I have a simple example for 'F0, which is a self-contained directory with every source needed (the header files are older version but should work). Look into the c.bat file how to run the compiler (I simply type "c blinky", but the path to compiler has to be modified).

JW

wb0gaz
Senior

Thank you JW for the reply.

I am now back to experimenting based on STM32CubeMX to generate minimal project (set two GPIO as output, nothing else), selecting Lower Level support (there is only two options, HAL and LL). This generated a project that will compile __disable_irq() and NVIC_EnableIRQ(USART1_IRQn). I can learn from this.

Also, this way I now have stm32f0xx_it.h, which was not present in "empty" configuration.

I realize now that the problems I am having are not with STM32 MCU, but rather are not sufficient understanding of STM32Cube IDE system.

Thank you for the links on www.efton.sk, these will be helpful, and I will study them.

Dave

TDK
Guru

You may have better luck by generating a project with CubeMX, then deleting everything HAL-related. There isn't much. This will give you a starting point that includes the appropriate CMSIS headers and basic startup functionality.

If you feel a post has answered your question, please click "Accept as Solution".
wb0gaz
Senior

Thank you, TDK.

I have done almost exactly that with STM32CubeMX (no pin assignments, just confirming clock configuration would be usable if necessary). I selected LL rather than HAL - the step for making that choice is not very detailed and buried in "advanced settings". I wish STM32CubeMX offered HAL, LL, "neither", or "advanced" options clearly offered when the project is first configured, and made it clear that the default choice is HAL (as appears to be the case.)

I placed all of my original code (from the various attempts to use "empty" configuration) ahead of the generated code. With this, the original code is working, and __disable_irq() (which was my first problem) also now compiles and works normally. There may be a small amount of residual data in the flash image (unless the compiler correctly identifies all of the code as unreachable and optimizes it out), however, that appears to be minimal at least.

Next step I will resume experimentation with USART1 interrupt function where I was previously stopped. I'd be very surprised if there is still a problem, as the various include structures were absent in my original "empty" configuration.

I expect I'll use HAL or LL for other projects in the future - they certainly are good options - however, in my current task I will be extremely memory constrained and dedicated to a specific low-end target device, so I want to control as many details as possible.

Thanks again for your contribution,

Dave

> You may have better luck by generating a project with CubeMX, then deleting everything HAL-related. There isn't much. This will give you a starting point that includes the appropriate CMSIS headers and basic startup functionality.

Isn't the resulting code dependent on chain of headers within Cube?

I've looked at a couple of the CubeF0 examples (which are admittedly not CubeMX-generated), and don't see "stm32f0xx.h" explicitly included.

JW

It's included in system_stm32xxx.c.
If you feel a post has answered your question, please click "Accept as Solution".