I'm using HAL drivers with code generated by CubeMX. In main routine I called HAL_UART_Receive_IT(). After transmitting data over UART (which is connected in a loopback fashion) I can see the module is receiving byte and setting RXNE bit in registers. However interrupt is not generated? I can't explain why... In HAL_UART_Receive_IT() function there is code enabling interrupts, so what's wrong?
You are not giving enough info and code in your question.
Anyway, in your stm32xx_hal_msp.c file you initialize your peripheral from hardware point of view: be sure to enable interrupts too
HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
HAL_NVIC_EnableIRQ(USART1_IRQn);
Then add
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1);
}
to your stm32xx_it.c file
Related
I have been unable to find an answer, possibly due to me being unable to put specific enough nomenclature on the involved processes.
I use Vitis HLS to synthesize designs where one call of the main function is one clock cycle long, being pipelined of course. This works fine for almost all of our cases. Where this is not possible (i.e. for components where we need to guarantee certain latencies / pipelining depths) I use verilog.
The goal is to transfer data via DMA to a Zynq-7000's memory and THEN issue an interrupt to let the PS know that the DMA transfer is finished.
Suppose I have a Vitis HLS project, where the PS can initiate a DMA transfer of uint32s using (a rising edge on a signal in) an s_axilite interface to my component, like in the code below:
#include <cstdint>
void Example
(
uint32_t *dmaRegion,
bool &intrSig,
volatile bool writeNow
)
{
#pragma HLS PIPELINE II=1
#pragma HLS INLINE RECURSIVE
#pragma HLS INTERFACE s_axilite port=return bundle=registers
#pragma HLS INTERFACE ap_ctrl_none port=return
#pragma HLS INTERFACE m_axi port=dmaRegion offset=slave bundle=x
#pragma HLS INTERFACE s_axilite port=dmaRegion bundle=registers
#pragma HLS INTERFACE ap_none port=dmaRegion
#pragma HLS INTERFACE s_axilite port=writeNow bundle=registers
#pragma HLS INTERFACE ap_none port=writeNow
#pragma HLS INTERFACE ap_none port=intrSig
static bool lastWriteNow { false };
static uint32_t Ctr { 0 };
bool intr = false;
if (!lastWriteNow && writeNow)
{
Ctr++;
dmaRegion[10] = Ctr;
intr = true;
}
intrSig = intr;
lastWriteNow = writeNow;
}
Now, this seems to work fine and cause a 1-clock-cycle-pulse interrupt as long as WREADY is driven high by the Zynq (and through a SmartConnect to my component) and I have found some examples where this is done this way. Also, the PS grabs the correct data from the DDR memory (L2 Data Cache has been disabled for this memory region) directly after the interrupt.
However, what will happen if for example more AXI masters are trying to drive the Smart Connect and cause congestion, effectively causing WREADY to go low for this component? In my tests, where I drove the WREADY signal of the AXI Smart Connect Master Interface to a constant zero to simulate (permanent) congestion, the interrupt signal (and WVALID) was driven to a permanent high, which would mean.... what? That the HLS design blocked inside the if clause? I do not quite get it as it seems to me that this would contradict the II=1 constraint (which is reported by Vitis HLS as being satisfied).
In a way it makes sense of course, since WVALID must go high when data is available and it must stay high until WREADY is high as well. But why the interrupt line goes (and stays) high no matter what even though the transaction is not yet finished evades me.
Is this at all possible with any guarantees about the m_axi interface, or will I have to find other solutions?
Any hint and information (especially background information about that behaviour) is very much appreciated.
Edit:
For example, this works fine:
but this causes the interrupt to stay high forever:
Of course, the transaction cannot finish. But it seems I have no way of unblocking the design so long as the AXI bus is congested.
Vitis Scheduler view
When I compile your code and look at the schedule view this is the result:
What I understand is that there is phi node (term borrowed from LLVM) which means that the value of intrSig can't be set before finishing the AXI4 write response. Since this is then converted into RTL the signal must have a value, and if it goes high, then there is congestion on the AXI4, it will stay high until the AXI transaction has finished.
HLS craziness
I tried to look into the HDL, with not much luck. I only got an intuition though which I try to share:
The red wires are the ones that eventually drive the intrSig signal. The flip flop is driven to 1 through the SET port, and to 0 by the RST port.
Long way to intrSig from this FF, but it eventually gets there:
The SET signal is driven by combinatorial logic using writeNow:
And lastly the wready goes a long way but it interferes to the pipeline chain of registers that eventually drives the intrSig.
Is this proof of what is happening? Unfortunately no, but there are some hints that the outcome of the m_axi transaction stops the interrupt pipeline to advance.
Some debugging hints
I don't know if clearing the wready signal actually simulates congestion, the axi protocol starts with a awready and I expect a congested interconnect to not accept transactions from the beginning.
Also, I would instantiate your IP alone, then attach some AXI VIP (axi verification IPs) which are provided in Vivado by Xilinx and programmed in SystemVerilog to give you the output you want, while recording all your data. You will also be able to look all the waveforms and detect where your issues are.
You can have your IP write into one of these AXI4VIP configured in slave mode, or you can write to a BRAM.
I'll leave here some documentation.
I have ATmega32 AVR and I want to have more Interrupt pins than (INT 0, INT 1, INT 2)
so Can I convert any pins in ATmega32 to an interrupt or there is another method to have more interrupts in the micro controller? Or should I get another AVR microcontroller?
INT0/INT1/INT2 and pins assigned to them in Atmega32 have special features, for example to wake up MCU from energy saving modes. If you need another interrupt with special feature but on diffrent pin then it is not possible, but... if you want to check input pin state and then execute some actions there is workaround that I used a few times.
So, how external interrupts works?
(Simplified, pseudo-description) There is a special hardware controller inside your MCU that detect rise-up/down, change of chosen pins and when certain condition is met, it reports to interrupt controller what happened, then if mask bit of this interrupt is set to enabled your MCU invokes interrupt vector (ISR).
So, how to workaround this?
Short explaination:
Use one of interrupts given by timer unit and set "faster" than signal on input can change.
Probe input states in timer ISR.
Whenever condition is met, for example high-state on pin for about 5 ms, you can save that fact in variable value.
Make callback to execute action or just make action inside your ISR, that depends about execution time of this action, ISRs should be short in execution time.
Pseudocode below (typed without compiling, just here in answer textbox):
#include <avr/io.h>
#include <avr/interrupt.h>
volatile int sth_happened = 0;
void ExecuteCallback(void)
{
// your action goes here
// reset sth_happened by assgining to 0
}
ISR(TIMER0_COMP_vect) // this ISR should be executed faster than signal on chosen pin can change
{
// check PIN of your pin here
// if state/signal on your pin met requirements,
// save it to variable or execute another code
// sth_happened = 1 / ExecuteCallback();
}
int main(void)
{
// Prepare your ISR timer here
// I would recommend to use CTC mode with desired execution time
sei(); // enable interrupts
while(1)
{
if (sth_happened) ExecuteCallback();
}
return 0;
}
You might consider just making the main loop in your program run faster so you can read those pins in your program and react when they change.
If you really need actual interrupts, you might consider switching to a newer AVR like the ATmega328P, where every I/O line can be used as a pin-change interrupt (PCINT) pin.
I see in STM32F103 series, the GPIO extra interrupt is set to the EXTI. And GPIOx_0 (x=A,B,C...)is set to EXTI0. Take an example, if I want to use PA0 and PB0 as interrupt input,can I set them to EXTI0 at the same time? I mean in the EXTI0_Handler function I read the value of the input register of PA0 and PB0 to judge which one input a electrical level I want to carry different function by using if...else. I use it in STM8 successfully but there seems a little problem in STM32. Can you help me? Thanks.
The answer explains the problem clearly. The picture takes an example that why the four bits will be changed if you set different pins. You can see that the four bit affect by each other status if you config other pins. I ignore this problem before.
If you look into the STM32F103 Reference Manual p. 209, you will see that there is actually a multiplexer that decides if PA0, PB0, ... or PG0 is connected to the EXTI0 signal:
STM32F103 ExtI0 schematic
That means that you cannot connect both PA0 and PB0 to EXTI0. In fact, there are four specific bits in the alternate function input/output register (AFIO) which let you choose which pin is connected to the EXTI0 signal. Here, these bits are located in the control register AFIO_EXTICR1. See the AFIO register map in the same document for further information.
Now I don't know which setup you are using, but as I recall, I had separate functions for different interrupt request routines (for EXTI0, EXTI1 and so on).
As the title says its not giving me any errors when i build and run in code composer, but nothing happens on the baord. It even says the normal : "MSP430: Flash/FRAM usage is 84 bytes. RAM usage is 80 bytes." The code is below, should just light up leds in pattern. Straight from textbook, tried other code also.
#include <msp430.h>
void main (void)
{
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
P2DIR = 0x18; // Set pins with LEDs to output, 0b00011000
P2OUT = 0x08; // LED2 (P2.4) on, LED1 (P2.3) off (active low!)
for (;;) { }
}
`
The compiler tells you how many bytes you code needs from the Flash and RAM Memory. But this output does not mean that, those byte have also been transfered to the chip.
So perhaps the easy answer is: After compiling the code you have to start the debugger which automatically transfers the programm to the chip's flash memory and starts it.
If you had done this already then, it could be possible that:
you have not chosen the right serial port (virtual USB to Serial?)
your driver (flash programmer over usb) is corrupt (Windows ?)
your MSP430 is RIP
if you use a lauchpad:
your lauchpad is damaged (especially the USB programmer part)
you removed the jumper that connect the USB Programmer with the chip' UART programming pins.
I am trying to use DMA for my UART Rx and Tx. Till now I had the freeRTOS version of the serial demo working fine. It still works fine. However, now I have incorporated the UART DMA example, from the example projects.
the code is conditionally compiled, so that when a switch _HAS_DMA == 1, only then the DMA engine is configured, ram buffers are configured, and default UART ISRs as required by the FreeRTOS demo are removed.
At this point, whenever I send a serial byte stream, the running project simply gets reset.
I am using MPLAB IDE 8.92, XC16 v1.20, Explorer-16 platform, dspic33fj256gp710 part.
The DMA code included does not use any FreeRTOS API calls.
I have setup the project so that StackOverflow is detected using the FreeRTOS configuration option. But the code does not reach the Stackoverflow hook function. I have also included the U2ErrInterrupt ISR to see if incoming bytes are coming in fine, however even that interrupt is not reached.
Has any one faced this before?
interestingly, the UART DMA Loopback example from Microchip website, which uses the MPLAB C30 compiler, works fine on my board.
any pointers on this one? I could not locate any code examples in the FreeRTOS forum on how to use the DMA for UART, but it is suggested to use this method in production code for efficiency.
Need help here.
Thanks and best regards,
Vishal
OK. I found the culprit. Its me. :)).
When setting up the DMA to receive UART interrupts, one should not enable UART interrupt separately in software. Which is what I was doing. In addition, I had conditionally un-compiled the UART ISRs from my code !!!. So in effect, whenever a byte was received by the UART engine, the processor is getting confused as to who will serve this interrupt, DMA or Application code. I thing the PC would point to the designated UART RX ISR vector location, where the processor would not find anything, and this was causing the reset. Or may be there was a race condition setup between the DMA and the processor to serve this interrupt, which was causing the reset.
Now that I have setup UART so that Interrupts are not enabled separately by application, when DMA is going to serve the UART RX, my code is working fine. I am yet to integrate the whole thing with FreeRTOS deferred interrupt processing using binary semaphores, but I hope I will not see any troubles there.
There is not much documented about this though...neither in Microchip manuals nor in the FreeRTOS examples.
Also, I found that when using DMA with UART, as per the manual, the DMA receives WORDS from the UART RX engine, with lower byte having the data, and upper byte having the status. If the DMA is also used for UART Tx, and is set to transfer WORDS to UART TXREG, the two intelligently manage to send only the lower data byte out. So the receiving party still gets expected bytes. This is also not documented well.
I will try to post my code here for future generations though :)).