Interrupt when UART tx buffer empty esp8266 (arduino) - interrupt

How can i set up a custom interrupt handler that is triggered when the TX buffer is emptied?

Related

UDR register always reads 0xFF

I have an ATTiny that is supposed to receive commands over UART. I have a simple display of eight LEDs that should show the contents of the most recent byte received. I am using an interrupt to read data as it is received. No matter what data I send UDR always reads 0xFF in the interrupt. I know the interrupt is being triggered since the display changes from 0x00 to 0xFF, but it never displays the value I sent over the serial bus.
This is how I enable UART.
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
This is the code in the interrupt. I have tested display() and it functions correctly on its own thus implying message is always 0xFF.
ISR(USART_RXC_vect) {
uint8_t message = UDR;
display(message);
}
I am confident that my computer is sending the correct information, but I have only tested it with a pseudo-terminal to print out the sent bytes. I intend to snoop the hardware connection with an oscilloscope, but I don't believe that is the issue. Is there something that is causing UDR to always read as 0xFF?
Edit:
I have snooped the connection with an oscilloscope and have verified that the computer is sending the correct data, at the correct rate. However, the ATTiny is not operating at the correct baud rate. At 2400 baud pulses should be about 400 microseconds long, however the microcontroller is producing pulses over 3 milliseconds long. This explains why it would always read 0xFF, the computer would send nearly the entire byte when the controller thought it was receiving the start bit, when the controller tried to read the remaining data the lines would be undriven, resulting in it reading all ones. I still don't know why this is the case as I believe I am properly setting the baud rate on the controller.
Edit:
The issue has been resolved. By default the clock prescaler is set to 8, so the device was only operating at 1MHz, not 8MHz. Setting the clock prescaler to 1 solved the problem.
There can be several problems with uart communication. First check some things:
Is controller configured with the right clock?
Internal/External
Is F_CPU defined for <util/setbaud.h>?
Is BAUD defined for <util/setbaud.h>?
Are you using a controller like ATmega16 that has special register access?
If you are using an external clock (that should not be devided) is CKDIV8 disabled in FUSES or in special registers at some controllers?
Is:
Baudrate,
Paritybit,
Stopbit
setup corret on Transmitter and Receiver
Debug:
If you are using a PC for communication, create a loopback at the UART adapter and check with a terminal (TeraTerm, Putty, ...) if the messages you send are received correctly.
You also can enable the TX controller and check if loopback is working on your uC.
If it is possible try to write the received data to some leds to check if some date is received
Is GND betweend receiver and transmitter connected?
Are the voltage levels between transmitter and receiver the same?
Do transmitter and receiver have its own source? (Then do not connect VCC!)
Check if the clock on the controller is correct (switch on an led with _delay_ms() function every second)
Example Program
#define F_CPU 12000000UL
#define BAUD 9600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
ISR(USART_RXC_vect)
{
volatile unsigned char message = UDR;
// If it is possible try to write the received data to
// LEDs (if there are some at your board)
display(message);
}
int main()
{
// To allow changes to clock prescaler it is necessary to set the
// CCP register (Datasheet page 23)!
CCP = 0xD8;
// RESET the clock prescaler from /8 to /1 !!!!
// Or it is necessary to divide F_CPU through the CLK_PRESCALER
CLKPSR = 0x00;
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1<<U2X);
#else
UCSRA &= ~(1<<U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
// Not necessary! Mostly ATmega controller
// have 8 bit mode initialized at startup
//UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
// If you are using ATmega8/16 it is necessary to do some
// special things to write to the UBRRH and UCSRC register!
// See ATmega16 datasheet at page 162
// Do not forget to enable interrupts globally!
sei();
while(1);
}
Please explain what the display() function is doing...

STM32L4R5xx hangs when an external interrupt is enabled

I would like to use the pin PC3 as an external interrupt. Whenever I enable the interrupt I end up in the infinite loop.
This is how I init a gpio and its interrupt:
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI3_IRQn);
I have checked hardware and all signals are like they should be.
I tried PB0 and PC3 and the result is the same.
Anyone who knows how to play with stm32l4 and exti?
The infinite loop:
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
I dont even reach an interrupt here (I have a break point there)
void EXIT3_IRQnHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
if(!HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_3))
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_14);
}
EXTI_ClearITPendingBit(EXTI3_IRQn);
}
Maybe that is important to mention that I also have SPI configuration in the same project (SPI1).
If ISR name is not correct it will use some default error code (its name depends on configuration), as happens in your case.
In my code its named EXTI3_IRQHandler not EXTI3_IRQnHandler.
Check in your startup file (in my setup it is called startup_stm32l432xx.s) for ISR names to be used.

STM32F303: Issue with USART interrupt triggering repeatedly after RS485 bus clash

I am having an issue with USART behaviour and am wondering if any of you can help! I am using an STM32F303 with three of its USARTs in use, of which USART1 is configured as an asynchronous RS485 port with its DE line controlled automatically. The TX, RX and DE pins from the microcontroller are connected to a TI SN65HVD1792 RS485 transceiver, which presents four lines (TX+, TX-, RX+, RX-) to the user for communication.
I am using interrupt-driven USART communication, which in most cases works absolutely fine. However, I am having an issue with handling the error condition in which the RS485 link is configured as two-wire (TX+/RX+ and TX-/RX- connected together, to form a +ve/-ve pair of wires used for both transmission and reception) and more than one device on the bus tries to transmit at the same time. When this happens, the STM32 stops responding to all serial communications until the power is cycled.
Looking a little bit closer at what is going on, I see that USART1_IRQHandler in stm32f3xx_it.c is being called repeatedly - over and over until I power-cycle the board. This calls HAL_UART_IRQHandler(&huart1) in stm32f3xx_hal_uart.c, the function of which is to check which interrupt has occurred (parity error, frame error, noise error, overrun, wakeup from stop, rx register not empty, tx ready, tx complete), deal with it appropriately, and then clear the interrupt state. However, none of these specific interrupts are recognised as having triggered - execution just passes by all the "if" statements, the function exits, and then runs again - endlessly.
I can't find any way of recognising that this has occurred, as it doesn't throw up any of the recognised error conditions. I'm aware that RS485 bus clash is something that should be avoided by good system design, but we can't rule out the possibility that it will happen when the system is in a customer installation - and it needs to be able to recognise the error, ignore the "clashed" message and continue - needing to power cycle it is unacceptable.
Does anyone have any ideas as to how to recognise this condition / stop the system from entering an interrupt loop?
Thanks in advance
The interrupt routine is as follows (HAL file version 1.2.0, date 13 Nov 15)
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
/* UART parity error interrupt occurred -------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_PE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_PE) != RESET))
{
__HAL_UART_CLEAR_IT(huart, UART_CLEAR_PEF);
huart->ErrorCode |= HAL_UART_ERROR_PE;
/* Set the UART state ready to be able to start again the process */
huart->State = HAL_UART_STATE_READY;
}
/* UART frame error interrupt occurred --------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_FE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
{
__HAL_UART_CLEAR_IT(huart, UART_CLEAR_FEF);
huart->ErrorCode |= HAL_UART_ERROR_FE;
/* Set the UART state ready to be able to start again the process */
huart->State = HAL_UART_STATE_READY;
}
/* UART noise error interrupt occurred --------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_NE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
{
__HAL_UART_CLEAR_IT(huart, UART_CLEAR_NEF);
huart->ErrorCode |= HAL_UART_ERROR_NE;
/* Set the UART state ready to be able to start again the process */
huart->State = HAL_UART_STATE_READY;
}
/* UART Over-Run interrupt occurred -----------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_ORE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_ERR) != RESET))
{
__HAL_UART_CLEAR_IT(huart, UART_CLEAR_OREF);
huart->ErrorCode |= HAL_UART_ERROR_ORE;
/* Set the UART state ready to be able to start again the process */
huart->State = HAL_UART_STATE_READY;
}
/* Call UART Error Call back function if need be --------------------------*/
if(huart->ErrorCode != HAL_UART_ERROR_NONE)
{
HAL_UART_ErrorCallback(huart);
}
/* UART wakeup from Stop mode interrupt occurred -------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_WUF) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_WUF) != RESET))
{
__HAL_UART_CLEAR_IT(huart, UART_CLEAR_WUF);
/* Set the UART state ready to be able to start again the process */
huart->State = HAL_UART_STATE_READY;
HAL_UARTEx_WakeupCallback(huart);
}
/* UART in mode Receiver ---------------------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_RXNE) != RESET) && (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE) != RESET))
{
UART_Receive_IT(huart);
/* Clear RXNE interrupt flag */
__HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
}
/* UART in mode Transmitter ------------------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_TXE) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TXE) != RESET))
{
UART_Transmit_IT(huart);
}
/* UART in mode Transmitter (transmission end) -----------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_TC) != RESET) &&(__HAL_UART_GET_IT_SOURCE(huart, UART_IT_TC) != RESET))
{
UART_EndTransmit_IT(huart);
}
}
The first thing I would do is to disable all of the interrupts you aren't explicitly using. At the very least, this should help identify the culprit. Do this with the macro __HAL_UART_DISABLE_IT() by passing in the interrupt you want to disable.
If that doesn't work, try confirming the TXE interrupt is being disabled by the UART_Transmit_IT() function being called by the IRQ. A quick way to figure out if this is the issue might be manually disabling the interrupt (while your issue is occurring) and seeing if the IRQ stops triggering. Otherwise, you could try breaking in the UART_Transmit_IT() function and seeing if the __HAL_UART_DISABLE_IT(huart, UART_IT_TXE); line gets executed. If the TXE interrupt isn't being properly disabled when finished, it will continue to trigger - causing something similar to what you're seeing.

How does Contiki OS process external interrupts?

It is possible to wake sensor nodes on external interrupts that are generated by peripheral sensors. The following explains how Contiki OS handles external interrupts. In case of the ATmega128RFA1 the external interrupts INT0 to INT4 are able to wake the MCU even from deep sleep.
an overview over processes and interupts in contiki is here:
https://github.com/contiki-os/contiki/wiki/Processes
http://de.slideshare.net/DingxinXu/contiki-introduction-iifrom-what-to-how
http://senstools.gforge.inria.fr/doku.php?id=os:contiki
contiki utilizes the ISR vectors of the MCU
this example is for ATmega128RFA1. the external interrupt is INT0 on PD0 (pin 25)
in the ISR the only action is to poll an associated contiki process. Internally this sends a poll request to the process. The process catches the poll request and then executes the calculations associated with the external interrupt. This proceeding prevents long lasting calculations in the ISR.
ISR :
ISR(INT0_vect)
{
process_poll(&extern_interupt_process);
PRINTF("interrupt was triggered on INT0... \n");
}
to enable the external interupts on INT0:
EIMSK = 0xb00000000; //disable interrupts before changing EICRA
EICRA |= 0xb00000011; //EICRA 0000|0011 rising edge triggers interrupt int0
EIMSK |= 0xb00000001; // enable INT0 (datasheet p. 219 ff)
process :
PROCESS(extern_interupt_process, "external_interrupt_process");
PROCESS_THREAD(extern_interupt_process, ev, data)
{
PROCESS_BEGIN();
while(1) {
PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);
// process data here
}
PROCESS_END();
}
use autostart_process() to start the extern_interrupt_process or start it manually in contiki-main.c
if the sensor has an open collector output activate the internal pull-up resistor and set the interrupt control register to trigger an interrupt on low-level (see this: wiring a sensor with open collector output)
DDRD &= 0xb00000000; // PD0 as input
PORTD |= 0xb00000001; // enable internal pull-up on PD0
EIMSK &= 0xb00000000; //disable interrupts before changing EICRA
EICRA &= 0xb00000000; //EICRA 0000|0000 low-level triggers interrupt on int0
EIMSK |= 0xb00000001; // enable INT0` (datasheet p. 219 ff)
http://en.wikipedia.org/wiki/Open collector

ADI BF533 programmable flag interrupt

When I press PF8 button, I want the blackfin goes into a ISR and the counter increases 1.
I should clear or set a bit which indicates the processor has entered the ISR, but I don't know how to clear it.
My processor is BF533.
Here is my code:
// prototype
EX_INTERRUPT_HANDLER(FlagA_ISR);
volatile int count = 0;
void main(void)
{
// Register FlagA ISR to interrupt vector group 12
register_handler(ik_ivg12, FlagA_ISR);
// set direction of programmable flag PF8 to input
*pFIO_DIR &= ~PF8;
ssync();
// interrupt enable PF8
*pFIO_INEN |= PF8;
ssync();
// give interrupt when FIO_FLAG_D PF8 changes
*pFIO_MASKA_D |= PF8;
ssync();
// Bind FlagA interrupt to IVG12
*pSIC_IAR2 |= 0x00005000; // flag A IVG12
ssync();
// Enable PFA in system interrupt mask register
*pSIC_IMASK = 0x00080000;
ssync();
// enable IVG12 in core interrupt mask register
*pIMASK |= 0x00001000;
ssync();
// wait for interrupt
while(count < 5);
printf("5 interrupts received");
}
EX_INTERRUPT_HANDLER(FlagA_ISR)
{
count++;
// Needed to clear or set a bit to indicate that the processor has entered the ISR
}
I have just figured out how to solve this question.
The PFx are connected to the FIO_FLAG. We can clear our interrupt status by clearing FIO_FLAG.
Here is the code:
*pFIO_FLAG_D &= ~PF8;
ssync();
//or, you can try:
*pFIO_FLAG_C |= PF8;
ssync();