I am trying to run UART1 interrupt on ESP32 WROVER but in process of compilation I get:
../main/scan.c: In function 'uart_intr_handle': ../main/scan.c:195:12: error: 'UART1' undeclared (first use in this function) status = UART1.int_st.val; // read UART interrupt Status
^~~~~ ../main/scan.c:195:12: note: each undeclared identifier is reported only once for each function it appears in ../main/scan.c:205:37: error: 'UART_RXFIFO_FULL_INT_CLR' undeclared (first use in this function); did you mean 'UART_FIFO_LEN'? uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
^~~~~~~~~~~~~~~~~~~~~~~~
UART_FIFO_LEN ../main/scan.c:205:62: error: 'UART_RXFIFO_TOUT_INT_CLR' undeclared (first use in this function); did you mean 'SPI_IN_DONE_INT_CLR'? uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
^~~~~~~~~~~~~~~~~~~~~~~~
SPI_IN_DONE_INT_CLR
Code that is generating this is:
/*
* Define UART interrupt subroutine to ackowledge interrupt
*/
static void IRAM_ATTR uart_intr_handle(void *arg)
{
uint16_t rx_fifo_len, status;
uint16_t i;
BaseType_t xHigherPriorityTaskWoken;
status = UART1.int_st.val; // read UART interrupt Status
rx_fifo_len = UART1.status.rxfifo_cnt; // read number of bytes in UART buffer
while(rx_fifo_len){
rxbuf[i++] = UART1.fifo.rw_byte; // read all bytes
rx_fifo_len--;
}
// after reading bytes from buffer clear UART interrupt status
uart_clear_intr_status(UART_NUM_1, UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR);
// a test code or debug code to indicate UART receives successfully,
// you can redirect received byte as echo also
//uart_write_bytes(EX_UART_NUM, (const char*) "RX Done", 7);
}
Example comes from: https://github.com/theElementZero/ESP32-UART-interrupt-handling/blob/master/uart_interrupt.c
What should I do to get UART1 variable?
Tnx for helping out!
Add this header:
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/uart.h"
#endif
Related
I'm trying to UART transceiver on my ZYNQ-7000 board using interrupts. Basically, it just take data from the serial terminal and send back to it.
After initialization, a message Uart Initialization Successful! is sent to and shown on the terminal which confirms that the ZYNQ can send data to the PC. But whenever I input some random letters, it seems that interrupt handler function, called void Handler(), was never called. It seems there is no interrupt generated at all. I've looked up a lot but cannot slove the problem. Could any one please help me with this, please.
Here is my code,
#include "xparameters.h"
#include "xuartps.h"
#include "xil_printf.h"
#include "xscugic.h"
#include "stdio.h"
// serial device ID
#define UART_DEVICE_ID XPAR_PS7_UART_1_DEVICE_ID
// interrupt ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
// serial port interrupt id
#define UART_INT_IRQ_ID XPAR_XUARTPS_1_INTR
// interrupt controller driver instance
XScuGic Intc;
// serial port driver instance
XUartPs Uart_Ps;
// data buffer size
#define MAX_LEN 512
u8 ReceivedBuffer[MAX_LEN];
volatile u32 ReceivedByteNum;
XUartPsFormat UartFormat = {
115200,
XUARTPS_FORMAT_8_BITS,
XUARTPS_FORMAT_NO_PARITY,
XUARTPS_FORMAT_1_STOP_BIT
};
// function declaration
int UartInit(XUartPs *uart_ps);
// interrupt handler
void Handler(void *call_back_ref);
int UartIntrInit(XScuGic *intc, XUartPs *uart_ps);
// main function
int main(void){
int status;
// initialize the serial port
status = UartInit(&Uart_Ps);
if(status == XST_FAILURE){
xil_printf("Uart Initialization Failed\r\n");
return XST_FAILURE;
}
// interrupt initialization
status = UartIntrInit(&Intc, &Uart_Ps);
if(status == XST_FAILURE){
xil_printf("Uart Initialization Failed\r\n");
return XST_FAILURE;
}
xil_printf("Uart Initialization Successful!\r\n");
// main loop
while (1) {};
return status;
}
int UartInit(XUartPs *uart_ps){
int status;
XUartPs_Config *uart_cfg;
uart_cfg = XUartPs_LookupConfig(UART_DEVICE_ID);
if(NULL == uart_cfg) return XST_FAILURE;
status = XUartPs_CfgInitialize(uart_ps, uart_cfg, uart_cfg->BaseAddress);
if(status != XST_SUCCESS) return XST_FAILURE;
// UART self test
status = XUartPs_SelfTest(uart_ps);
if(status != XST_SUCCESS) return XST_FAILURE;
XUartPs_SetOperMode(uart_ps, XUARTPS_OPER_MODE_NORMAL);
XUartPs_SetDataFormat(uart_ps, &UartFormat);
XUartPs_SetFifoThreshold(uart_ps, 32);
XUartPs_SetRecvTimeout(uart_ps, 8);
return XST_SUCCESS;
};
// UART Interrupt handler service
void Handler(void *call_back_ref){
xil_printf("Enter INTR\r\n");
XUartPs *uart_instance_ptr = (XUartPs *) call_back_ref;
u32 ReceivedCount = 0;
u32 IsrValue;
IsrValue = XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_IMR_OFFSET);
IsrValue &= XUartPs_ReadReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET);
// if interrupt is asserted
if( IsrValue & ((u32) XUARTPS_IXR_RXOVR) ){
XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_RXOVR);
ReceivedCount = XUartPs_Recv(&Uart_Ps, ReceivedBuffer, MAX_LEN);
ReceivedByteNum += ReceivedCount;
}
else if( IsrValue & ((u32) XUARTPS_IXR_TOUT) ){
// Rx FIFO timeout / idle
XUartPs_WriteReg(uart_instance_ptr->Config.BaseAddress, XUARTPS_ISR_OFFSET, XUARTPS_IXR_TOUT);
ReceivedCount = XUartPs_Recv(&Uart_Ps, ReceivedBuffer, MAX_LEN);
ReceivedByteNum += ReceivedCount;
// send out
for(u32 sendByte=0;sendByte<ReceivedByteNum;sendByte++){
XUartPs_SendByte(XPAR_PS7_UART_1_BASEADDR, ReceivedBuffer[sendByte]);
}
ReceivedByteNum = 0;
}
}
// UART Interrupt init
int UartIntrInit(XScuGic *intc, XUartPs *uart_ps){
int status;
// initialize the interrupt controller
XScuGic_Config *intc_cfg;
intc_cfg = XScuGic_LookupConfig(INTC_DEVICE_ID);
if(NULL == intc_cfg) return XST_FAILURE;
status = XScuGic_CfgInitialize(intc, intc_cfg, intc_cfg->CpuBaseAddress);
if(status != XST_SUCCESS) return XST_FAILURE;
// set and enable interrupt exception handle function
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler) XScuGic_InterruptHandler, (void *) intc);
// set interrupt handler for interrupt
XScuGic_Connect(intc, UART_INT_IRQ_ID, (Xil_ExceptionHandler) Handler, (void *) uart_ps);
// set interrupt trigger mode
XUartPs_SetInterruptMask(uart_ps, XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT);
Xil_ExceptionEnable();
XScuGic_Enable(intc, UART_INT_IRQ_ID);
return XST_SUCCESS;
}
I'm using UART1 controller at MIO 48, 49 which is confirmed at both the Vivado and the schematic.
There are few problems of your program.
Receive function
It seems you have not called the UART receive function (XUartPs_Recv).
In interrupt mode, the UART controller will start receiving after you called XUartPs_Recv, this function is non-blocking. When all data received, the UART controller will generate an interrupt, and all data has been written to the receive buffer by the interrupt handler function.
XUartPs_Recv(uart_ps, RecvBuffer, SIZE_IN_BYTE);
Interrupt Handler
UARTPS library provided the interrupt handler function (XUartPs_InterruptHandler). So you need to bind it to the XScuGic
XScuGic_Connect(intc, UART_INT_IRQ_ID,
(XInterruptHandler) XUartPs_InterruptHandler, uart_ps);
This interrupt handler can help you receive the data from UART FIFO and write to the receive buffer.
Custom Callback
If you want to do something when the interrupt occoured, you don't need to write a new handler function by yourself, but a Callback function is needed.
XUartPs_SetHandler(uart_ps, (XUartPs_Handler)Handler, uart_ps);
Use this function, your custom handler will be called from the
interrupt context (XUartPs_InterruptHandler) when data has been sent or received.
Addition
You may set the receiver timeout. If it is not set, and the last few bytes of data do not trigger the over-water or full interrupt, the bytes will not be received. By default it is disabled.
XUartPs_SetRecvTimeout(uart_ps, 8);
Reference
Please refer the official example by Xilinx on GitHub.
I've been trying to implement a basic per-byte UART Rx Interrupt on a STM32F4 board using HAL skeleton code generated by STMCubeMX version 4.26.0
Quite simply - I want to receive a character in UART1 via an Rx interrupt and transmit it on UART 6
I have successfully implemented a polled version of what I want to achieve
uint8_t in_usart1[10];
HAL_StatusTypeDef usart1_status;
usart1_status = HAL_UART_Receive(&huart1, in_usart1, 1, 1);
if (usart1_status != HAL_TIMEOUT)
{
HAL_UART_Transmit(&huart6, in_usart1, 1, 100);
}
I've enabled the UART 1 NVIC interrupt in STMCubeMX and stm32f4xx_it.c contains the IRQ handler which I've added my own user handler to:
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
HAX_USART1_IRQHandler(&huart1); /* My Handler */
/* USER CODE END USART1_IRQn 1 */
}
I've seen lot's of commentary about UART_Receive_IT() - but I suspect this is based on older versions of HAL due to UART_Receive_IT() being defined in stm32f4xx_hal_uart.c
My suspicion is that I need to enable to interrupt / clear the interrupt flag as when I debug, USART1_IRQHandler() is NEVER called
Does any one have any code that demonstrates what I am trying to achieve? My google-foo has failed me
EDIT:
I've gotten a little closer... In main.c I added (comments are existing code)
/* USER CODE BEGIN PV */
uint8_t rx_buffer;
/* USER CODE END PV */
...
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)rx_buffer, 10);
/* USER CODE END 2 */
And then created:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
HAL_UART_Transmit(&huart6, &rx_buffer, 1, 100);
}
}
Now the Rx interrupt gets fired - but it's a bit flakey on the USART6 Tx, and the Rx interrupt only gets fired once
Do not block HAL_UART_RxCpltCallback for a long time! Just set a flag and check it and then send data from the main function.
And rx_buffer is variable so correct call HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);
For anybody stumbling across this question, the answer is embarrassingly simple. I have two UARTs - One I was using an Rx Interrupt, and the other using DMA.
Turns out the one I thought I had configured for Interrupt was actually configured for DMA and visa-versa...
In STMCubeMX
- USART1 (RS485) has DMA Tx and DMA Rx enabled
- USART6 (Debug - RS232) has global interrupt enabled
In main.c
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
/* USER CODE END 2 */
I have a user_main.c which has the following code:
#include <string.h>
#include "stm32f4xx_hal.h"
extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart6;
UART_HandleTypeDef *debug_uart(void)
{
return &huart6;
}
UART_HandleTypeDef *rs485_uart(void)
{
return &huart1;
}
#define BUFFER_SIZE 1
uint8_t debug_rx_buffer[BUFFER_SIZE];
uint8_t debug_tx_buffer[BUFFER_SIZE];
uint8_t rs485_rx_buffer[BUFFER_SIZE];
uint8_t rs485_tx_buffer[BUFFER_SIZE];
static void rs485_tx(uint8_t *tx_buffer, uint16_t len)
{
HAL_UART_Transmit_DMA(rs485_uart(), tx_buffer, len);
}
static void debug_tx(uint8_t *tx_buffer, uint16_t len)
{
HAL_UART_Transmit(debug_uart(), tx_buffer, len, 1000);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == debug_uart())
{
memcpy(rs485_tx_buffer, debug_rx_buffer, BUFFER_SIZE);
rs485_tx(rs485_tx_buffer, BUFFER_SIZE);
HAL_UART_Receive_IT(debug_uart(), debug_rx_buffer, BUFFER_SIZE);
}
else if (huart == rs485_uart())
{
memcpy(debug_tx_buffer, rs485_rx_buffer, BUFFER_SIZE);
debug_tx(debug_tx_buffer, BUFFER_SIZE);
HAL_UART_Receive_DMA(rs485_uart(), rs485_rx_buffer, BUFFER_SIZE);
}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == debug_uart())
{
}
else if (huart == rs485_uart())
{
}
}
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)
{
}
The memcpy()'s may not be strictly required, but they do provide a level of isolation between all the buffers. Technically, there probably should be semaphores providing even more protection...
Note that I DO NOT use HAL_UART_Transmit_IT() for the debug UART - If you want to use HAL_UART_Transmit_IT (i.e. interrupt generated on completion of Tx), you will need to write code that handles transmission of characters from a circular buffer
I have to make tasks as processes in Linux but I don't want the process to execute until all the processes are created. So I thought of moving the processes to wait queue soon after creation and wait until all processes are created.
#include <unistd.h> /* Symbolic Constants */
#include <sys/types.h> /* Primitive System Data Types */
#include <errno.h> /* Errors */
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* POSIX Threads */
#include <string.h> /* String handling */
#include <sched.h>
#include <linux/kernel.h>
#include <time.h>
#include <sys/resource.h>
#include <stddef.h>
#include <linux/sched.h>
#include <linux/wait.h> /* for wait_event_interruptible() & wake_up_interruptible() */
int done = 0;
static DECLARE_WAIT_QUEUE_HEAD(queue);
int main()
{
int pid1, pid2;
if ((pid1 = fork()) < 0) //create a child process
exit(1);
if ((pid2 = fork()) < 0) //create a child process
exit(1);
if (pid1 == 0) //child process
{
wait_event_interruptible(queue, done == 2);
printf("child 1\n");
}
else //parent process
{
done = done+1;
wake_up_interruptible(&queue);
}
if (pid2 == 0) //child process
{
wait_event_interruptible(queue, done == 2);
printf("child 2\n");
}
else //parent process
{
done = done+1;
wake_up_interruptible(&queue);
}
return 0;
}
But when I tried this sample code it shows these errors.
$ gcc -Wall try.c
try.c:18:8: warning: type defaults to ‘int’ in declaration of ‘DECLARE_WAIT_QUEUE_HEAD’ [-Wimplicit-int]
try.c:18:1: warning: parameter names (without types) in function declaration [enabled by default]
try.c: In function ‘main’:
try.c:33:6: warning: implicit declaration of function ‘wait_event_interruptible’ [-Wimplicit-function-declaration]
try.c:33:31: error: ‘queue’ undeclared (first use in this function)
try.c:33:31: note: each undeclared identifier is reported only once for each function it appears in
try.c:39:2: warning: implicit declaration of function ‘wake_up_interruptible’ [-Wimplicit-function-declaration]
try.c: At top level:
try.c:18:8: warning: ‘DECLARE_WAIT_QUEUE_HEAD’ declared ‘static’ but never defined [-Wunused-function]
When I checked $ man wait_event_interruptible, it says "No manual entry for wait_event_interruptible". So the API is missing in the library. How can I add it to the library? Thanks in advance.
wait_event_interruptible(), wake_up_interruptible() are some of the Kernel's API to create and use wait queues. You cannot use those from the user-land!
If I understand your purpose correctly, what you need to do is to create N processes barrier. If you know the number of the processes (N), you can easily use semaphores: initialize the semaphore with zero, all processes call down() and the last process calls up() N times. You can also use message queues.
You can also use the Linux API for barriers: pthread_barrier_wait and pthread_barrier_init, but I have not used this before.
I am trying to use the Arduino time scheduler. I copied the code from here and I imported the library, but it didn't compile. Here's the compilation error code and the code itself:
Error:
In file included from time2.ino:1:
C:\arduino\arduino-1.0.3\libraries\Scheduler/Scheduler.h:62: error: 'byte' does not name a type
C:\arduino\arduino-1.0.3\libraries\Scheduler/Scheduler.h:64: error: 'NUMBER_OF_SCHEDULED_ACTIONS' was not declared in this scope
C:\arduino\arduino-1.0.3\libraries\Scheduler/Scheduler.h:65: error: 'byte' does not name a type
Code:
#include <Scheduler.h> // [url=http://playground.arduino.cc/uploads/Code/Scheduler.zip]Scheduler.zip[/url]
Scheduler scheduler = Scheduler(); //create a scheduler
const byte ledPin = 13; //LED on pin 13
void setup(){
Serial.begin(9600); //Iitialize the UART
pinMode(ledPin,OUTPUT); //set pin 13 to OUTPUT
}
void loop(){
scheduler.update(); //update the scheduler, maybe it is time to execute a function?
if (Serial.available()){ //if we have recieved anything on the Serial
scheduler.schedule(setHigh,500); //schedule a setHigh call in 500 milliseconds
Serial.flush(); //flush Serial so we do not schedule multiple setHigh calls
}
}
void setHigh(){
digitalWrite(ledPin,HIGH); //set ledPin HIGH
scheduler.schedule(setLow,500); //schedule setLow to execute in 500 milliseconds
}
void setLow(){
digitalWrite(ledPin,LOW); //set ledPin LOW
}
How can I fix this?
the library is not 1.0.0+ compliant.
Change replace the following .\Scheduler\Scheduler.h :
< #include <WProgram.h>
---
> #if defined(ARDUINO) && ARDUINO >= 100
> #include "Arduino.h"
> #else
> #include "WProgram.h"
> #endif
Then it will compile, for me at least.
I have been working with this code for days and cannot figure out why my interrupts are not being triggered. I know data is coming through successfully because I used a probe on a logic analyzer, also my baud rate is correct as I can transmit with UART successfully.
At this point I'm lost, I've read the datasheet over and over and can't figure out my problem. I will try to include only the relative code but enough that you can see how things work in my project.
Please let me know if you see issues with this code.
Thank you!
Code snippets from main.c:
// USART RX interrupt priority
IPR1bits.RCIP = 0;
IPR1bits.TXIP = 0;
// configure the hardware USART device
OpenUSART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT &
USART_CONT_RX & USART_BRGH_LOW, 14);
Code snippets from interrupts.c
//----------------------------------------------------------------------------
// Low priority interrupt routine
// this parcels out interrupts to individual handlers
#pragma code
#pragma interruptlow InterruptHandlerLow
// This works the same way as the "High" interrupt handler
void InterruptHandlerLow() {
// check to see if we have an interrupt on USART RX
if (PIR1bits.RCIF) {
PIR1bits.RCIF = 0; //clear interrupt flag
uart_recv_int_handler();
}
// check to see if we have an interrupt on USART TX
if (PIR1bits.TXIF && PIE1bits.TXIE) {
// cannot clear TXIF, this is unique to USART TX
// so just call the handler
uart_tx_int_handler();
}
}
UART RX Interrupt Handler snippet:
void uart_recv_int_handler() {
int msgLen;
//if (DataRdyUSART()) {
uc_ptr->buffer[uc_ptr->buflen] = RCREG;
//uc_ptr->buffer[uc_ptr->buflen] = ReadUSART();
uc_ptr->buflen++;
}
}
Did you
- Set trisC6/7 correctly?
- if you have a part with analog inputs multiplexed on those pins, did you disable them?
- Is your BRG value validated for this part and these oscillator settings?
See also
http://www.piclist.com/techref/microchip/rs232.htm
I migrated to dspic, but I used to do the serial receive under interrupt. This I had in the interrupt (serialin1 is a power of two circular buffer, lastserialin1 the pointer into it, and ser1bufinmask is size of buffer-1)
if (PIR1bits.RCIF == 1) /* check if RC interrupt (receive USART) must be serviced
{
while (PIR1bits.RCIF == 1) /* flag becomes zero if buffer/fifo is empty */
{
lastserialin1=(lastserialin1+1)&ser1bufinmask;
serialin1[lastserialin1]=RCREG;
}
}
To initialize the uart I had:
// Configure USART
TXSTA = 0x20; // transmit enable
RCSTA = 0x90; // spen en cren
RCONbits.IPEN = 1; /* Interrupt Priority Enable Bit. Enable priority levels on interrupts */
INTCONbits.GIE = 1; /* Set GIE. Enables all high priority unmasked interrupts */
INTCONbits.GIEL = 1; /* Set GIEL. Enables all low priority unmasked interrupts */
TRISCbits.TRISC6 = 0; // page 237
TRISCbits.TRISC7 = 1; // page 237
Open1USART (
USART_TX_INT_OFF
&
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT & // 8-bit transmit/receive
USART_CONT_RX & // Continuous reception
// USART_BRGH_HIGH, 155); // High baud rate, 155 eq 19k2
USART_BRGH_HIGH, brgval); // High baud rate, 25 eq 115k2
IPR1bits.RCIP = 0;
PIR1bits.RCIF = 0;
with brgval calculated using
#define GetInstructionClock() (GetSystemClock()/4)
#define GetPeripheralClock() GetInstructionClock()
// See if we can use the high baud rate setting
#if ((GetPeripheralClock()+2*BAUD_RATE)/BAUD_RATE/4 - 1) <= 255
#define BRGVAL ((GetPeripheralClock()+2*BAUD_RATE)/BAUD_RATE/4 - 1)
#define BRGHVAL (1)
#else // Use the low baud rate setting
#define BRGVAL ((GetPeripheralClock()+8*BAUD_RATE)/BAUD_RATE/16 - 1)
#define BRGHVAL (0)
#endif