Setting up UART interrupt to trigger when character is received - c

i am trying to setup an UART interrupt to trigger when a character is entered on the UART screen. The thing is the way i have set it up it seems that the interrupt triggers when transmitting and receiving. I have read the data sheet and it doesnt really say if it can be done and how. Its just says that a interrupt for serial port is avaiable.
This is how i have set up the uart
S0CON = 0x50;
PCON |= 0x80; /* Double Baud rate */
ADCON0 |= 0x80; /* Use baudrate generator */
S0RELL = 0xCC; /* Baudrate = 9614 Baud # 16Mhz */
S0RELH = 0x03;
TI0 = 1; /* Ready to transmit */
ES0 =1;
Does anyone possibly have any idea how this can be accomplished??
I am using Keil compiler and the Infineon C509
Datasheet **link fixed
Thank you

Unfortunately, it doesn't look like you'll be able to do what you want cleanly. Taking a look at the user manual--the data sheet is typically insufficient for this type of problem--check out Figure 7.4. The send and receive interrupt flags set by hardware for channel 0, TI0 and RI0, both trigger the default serial communication interrupt, and it doesn't appear that either can be disabled.
There might be other options, but I'd consider one of the following:
Polling (vs. using any interrupts for the UART)
Use the interrupt as you have it working, but check first thing in your serial comms interrupt that RI0 is set and if it's not, exit immediately. (Just make sure there's not any kind of timing problem with respect to this and clearing the receive flag to make sure you don't have any potential for dropping a byte.)
Link to C509-L user manual (not sure how long it'll persist): Infineon product site

Related

Proper use of SPI functions in RP2040 C/C++ SDK with PGA2310 volume control IC

I've been working on a project where I use a PGA2310 volume control IC to set the volume of an audio signal. The chip's interface is supposedly SPI, but no matter how much I try, I just can't seem to get it right. The chip takes a 16 bit word over SPI that contains the left and right channel volume information.
I'm wondering if I am using the sdk all wrong and my code is whacked.
I guess my question is: Am I setting up and using the SPI functions correctly?
Here is my code
/**
* SPI interface for PGA2310 volume control ic
*/
#include "pico/stdlib.h"
#include "hardware/spi.h"
#include "pico/time.h"
const int CS = 0;
const int SDI = 1;
const int SCLK = 2;
const int LED_PIN16 = 16;
const int LED_PIN25 = 25;
uint16_t PGA2310();
uint16_t PGA2310() {
int baud = 1600000;
// SPI inistalization
spi_init(spi0, baud);
spi_set_format(spi0, 16, SPI_CPOL_0 , SPI_CPHA_0, SPI_MSB_FIRST);
// Sets SPI pins
gpio_set_function(CS, GPIO_FUNC_SPI);
gpio_set_function(SDI, GPIO_FUNC_SPI);
gpio_set_function(SCLK, GPIO_FUNC_SPI);
// Sets LED pins
gpio_init(LED_PIN16);
gpio_set_dir(LED_PIN16, GPIO_OUT);
gpio_init(LED_PIN25);
gpio_set_dir(LED_PIN25, GPIO_OUT);
// Data to send to chip. only sending first 8 bits for right channel.
// This is because I am currently just testing the output of the right channel
uint16_t high = 255;
uint16_t low = 100;
// Test by toggling between high and low volume states with LED indicators
while (true) {
gpio_put(LED_PIN25, 1);
spi_write16_blocking(spi0, &high, 1);
sleep_ms(2000);
gpio_put(LED_PIN25, 0);
spi_write16_blocking(spi0, &low, 1);
sleep_ms(2000);
}
}
I've tried a bunch of different methods that I found online for using SPI with the pico SDK. I've tried just sending 8 bits.
Let me know if more info is needed.
As explained in comments, SPI normally consists of 4 signals: /SS, SCLK, MOSI and MISO.
/SS = slave select, also known as chip select. Almost always active low.
SCLK = serial clock.
MOSI = Master Output Slave Input. The main data line. Your MCU seems to call this SDO (serial data out?).
MISO = Master Input Slave Output. Optional signal for duplex (two way) communication SPI. Your MCU seems to call this SDI (serial data input).
In this case the MCU is the master so you should be using MOSI/SDO. A MCU is almost always the master, except when communicating with other MCUs.
Additionally, always double check which CPOL and CPHA settings that the slave expects. Getting these wrong is a classic problem and can lead to subtle "clock skew" problems where everything works fine most of the time, then fail and give corrupt data intermittently.
The names you pick for variables/constants in C code do not have any effect on the hardware and they disappear as soon as the code is compiled. The most important thing is that you understand how the hardware works, read the documentation for the RP2040 SDK functions you are calling, and then pass the correct values to the RP2040 SDK functions.
The biggest problem is that you need to rethink every pin assignment. The RP2040 hardware SPI pin functions are defined in column F1 of the "GPIO Functions" section of the RP2040 datasheet. Here is an excerpt from that table:
This table tells us, for example, you cannot use pin 0 as the SPI0 CS function. If you assign that pin to be an SPI pin, it will be the SPI0 RX (data receiving) pin.
At a minimum, you need to pick one pin to be the SPI0 SCK pin and another to be the SPI0 TX pin, and you must connect those pins from the RP2040 to the equivalent pins on your device. Then you might also need to pick an RP2040 pin to control the CS pin on your device, if it has one. On the RP2040 side, this pin would be configured as a GPIO output pin and you would drive it low or high to enable your device. Refer to your device's datasheet for details about what signals it expects on its inputs and then use an oscilloscope to make sure you are generating compliant signals.
Another problem is that the spi_write16_blocking is probably modifying your high and low variables, so you will probably need to set those to the right values before each time that you use them. (So there is no point in having two different variables like that, just have one.)

How do I reset the STM32 HAL UART driver (HAL) state?

I know one can enable a UART receive interrupt using
HAL_UART_Receive_IT(&huart2, (uint8_t *)rx_buffer, expectedNumberOfBytes)
But once started how does one stop it, "manually"?
We can disable the UART interrupt using HAL_NVIC_DisableIRQ() (ex: HAL_NVIC_DisableIRQ(USART1_IRQn)). This will prevent it from raising an interrupt, but the state set by the function HAL_UART_Receive_IT which is HAL_UART_STATE_BUSY_RX needs to be set back to HAL_UART_STATE_READY for the uart handle to go back to a state that can accept a new HAL_UART_Receive_IT() call.
Question
How do I reset the state of the UART interrupt if I wish to disable a Rx interrupt after some time?
Stack Overflow questions do not address how to reset the state; I have referred to these questions:
Disabling interrupt in interrupt handler STM32F407
https://electronics.stackexchange.com/questions/100073/stm32-usart-rx-interrupts
I could use USART_ClearITPendingBit() or USART_ITConfig() but these are defined as private functions by STM's HAL library. So should I use them?
How [do I] reset the state of the UART interrupt if [I] wish to disable a Rx interrupt after some time[?]
(See it's usage in "stm32f4xx_hal_uart.c", for example.)
The huart->RxState member of a uart handle struct is really only used internally by the HAL library when doing things such as HAL_UART_Receive(), HAL_UART_Receive_IT(), HAL_UART_Receive_DMA(), (and many other internal functions like this), etc. If you manually implement your own interrupt-based and ring-buffer-based UART Tx and Rx calls, however, which is the preferred way to do it, this member is completely meaningless and it doesn't matter what you do with it, as it is used only inside HAL library function calls and HAL ISR handlers (neither of which you have to use), and really has nothing to do with the register-level interrupts and things directly.
By digging around the source code in stm32f4xx_hal_uart.c (for example), however, here are a couple valid options you can use:
1. How to reset huart->RxState to HAL_UART_STATE_READY:
Call HAL_UART_Init(). By inspecting its source code, you'll see it calls huart->RxState= HAL_UART_STATE_READY; before returning.
Just manually set huart->RxState = HAL_UART_STATE_READY; So long as you know you have properly stopped the interrupt-based receive in the middle of its processing, this is perfectly valid.
Let's take this further, however.
Imagine you are using UART7 on an STM32F4. Therefore, in your stm32f4xx_it.c interrupt handler file, you'll see the following code auto-generated by STM32CubeMX:
/**
* #brief This function handles UART7 global interrupt.
*/
void UART7_IRQHandler(void)
{
/* USER CODE BEGIN UART7_IRQn 0 */
/* USER CODE END UART7_IRQn 0 */
HAL_UART_IRQHandler(&huart7);
/* USER CODE BEGIN UART7_IRQn 1 */
/* USER CODE END UART7_IRQn 1 */
}
Let's go over some layers of disabling/enabling interrupts.
2. From broadest to narrowest scope, here are several ways to disable/enable the USART Rx interrupt:
You can disable/enable ALL interrupts, including this UART7_IRQHandler(), using these ARM-core CMSIS calls:
__disable_irq();
__enable_irq();
Source: https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/
So, you could do the following to disable the interrupt, reset the RxState, and then start up the interrupt-based receive again when ready:
__disable_irq();
huart7->RxState= HAL_UART_STATE_READY;
__enable_irq();
HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
You can disable/enable ONLY the UART7_IRQHandler() interrupts (all 10 types of uart7 interrupts connected to this interrupt vector, including Tx-related, Rx-related, error-related, etc), using these STM32 HAL calls:
HAL_NVIC_DisableIRQ(UART7_IRQn);
HAL_NVIC_EnableIRQ(UART7_IRQn);
Then, do the same as just above except use these calls to disable/enable the interrupts instead.
If you dig down into the implementation of HAL_UART_IRQHandler(), however, which is called by UART7_IRQHandler(), you'll see that it only calls the interrupt-based receive handler, UART_Receive_IT(), if both the USART_SR_RXNE bit ("Receive Not Empty", inside the USART Status Register) and the USART_CR1_RXNEIE bit ("Receive Not Empty Interrupt Enable", inside the USART Control Register 1), are both set. The RXNE bit is set whenever a byte comes in, and is cleared whenever you read the data register or write a zero to it. The interrupt-enable bit is something you have full control over to disable this UART receive interrupt, and if you clear this bit manually, you will disable the receive interrupt withOUT disabling any other type of interrupt associated with this USART. This is the best way to do it, as there are 10 interrupt sources associated with this UART. In other words, clearing this bit not only causes the check inside HAL_UART_IRQHandler() to fail, but it also prevents the receive interrupt from happening in the first place! Refer to the Reference Manual RM0090 Rev 16, for example:
p969:
p1009:
p1011:
p1015:
p1013:
So, to disable/enable the USART Receive Not Empty interrupt only, do the following. Refer to the Control Register (USART_CR1) on p1013, shown just above.
// Disable the USART Receive Not Empty interrupt
CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
// Enable the USART Receive Not Empty interrupt
SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
Now, you could do the following to disable the USART Receive interrupt, reset the HAL RxState, and then start up the interrupt-based receive again when ready:
CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
huart7->RxState= HAL_UART_STATE_READY;
SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE); // This call isn't actually necessary, as this bit is set inside `HAL_UART_Receive_IT()` as well
HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
3. How to (awkwardly) use HAL_UART_Receive_IT() for continual interrupt-based receiving.
TODO
4. Why HAL_UART_Receive_IT() really isn't a very useful function after-all.
TODO
5. How to manually configure your own interrupt-based UART Tx and Rx ISRs and functions.
TODO
You can use HAL_UART_Abort_IT.
Most UARTs clear any pending Receive interrupt when the program reads from the holding register. So my answer would be: simply read the data register after disabling interrupts, and ignore the result.
I haven't had a chance to try this on my STM32 yet, but...
There is a function static void UART_EndRxTransfer(UART_HandleTypeDef *huart)
in the HAL library that does the following:
Disable RXNE, PE and ERR interrupts
restore huart->RxState to Ready
I found that function in the stm32f7xx_hal_uart.c file. However, it is defined as static, so I just copied over the definition into the file where I used it. It might be a bit hacky but it worked for me.

What is the best way to control RS485 Tx enable on ZYNQ, FPGA

I am testing infrared temperature sensor. It is connected to SP485(converter rs485 to rs232?) which is connected to ZYNQ,FPGA.
enter image description here
I have to input High when I send Tx. After all of messages was sent, I will input Low to this Enable pin.
Simple approach is to do with one bit width GPIO.
Make High just before Write(). After Write() is finished, make GPIO LOW.
I thought..it will be work. but it wasn't.
Code is like as below...(I use libmodbus library to communicate using rs485)
write(fd,"1",1); // make gpio(enable pin) high.
req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t)); //write
write(fd,"0",1);//After write(), make gpio low to receive messages from sensor.
int response_length = modbus_receive_confirmation(ctx, rsp);
This code was not working properly. Write() is not write immediately..
or the prosess is working independently.(so there is possibility that when I input Low, write() is not finished).
I don't know reason actually. it's just my assuming.
So I added usleep();
write(fd,"1",1); // make gpio(enable pin) high.
req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t)); //write
usleep(9050); //waite until write is finished
write(fd,"0",1);//After write(), make gpio low to receive messages from sensor.
int response_length = modbus_receive_confirmation(ctx, rsp);
this code is working sometimes..... it also not the best answer.
the result is https://www.youtube.com/watch?v=Bqzu3hi9gV4
After 1'22, it's working.
enable Pin is connected to FPGA (ZYNQ)
It is difficult to add other circuit to control enable pin.
it is more convenience to make a design on the FPGA.
( i.stack.imgur.com/f7Ebg.png )
should I control this by software?(controlling gpio)
or Hardware?
Let me know the best way, approach.. Thank you.

Only two IO port interrupts for Xmega (INT0 and INT1)

In avr Xmega device, there are only two IO port interrupt vectors INT0 and INT1.
I have three switches that should generate three interrupts.
I have written an interrupt code for the first switch using INT0. Now, I can write the second interrupt using INT1 which will exhaust my vectors.
Below is my code for INT0 ISR:
ISR (PORTD_INT0_vect){
PORTD.INTFLAGS = 0x01; // clear INT0IF flag.
PORTD_OUT = PORTD_OUT | (1<<4); // led on.
}
Can I redefine this ISR to enable interrupt for second switch?
The registers that I set in main function are as follows:
PORTD.INT0MASK = 0x04; // PD2 is the source of interrupt for INT0.
PORTD.INTCTRL = 0x03; // Disable INT1, enable INT0 and place it a high-priority level.
PORTD.PIN2CTRL = 0x03; // configure PD2 pin to interrupt on the low level of signal.
PMIC.CTRL = 0x07; // enable high,medium, and low level interrupts.
sei(); // enable interrupt globally.
The idea of the external interrupts is that you get to know that something happened, but not what happened. In your ISR you have to read out the state of the inputs the switches are connected to and determine based on the readout, what to do. To detect, if the state did alter, keep a copy of the ports input status and do an XOR with the newly read out value (do this for a whole port, not just for single pins).
I'm not expert of XMEGA, but I can suggest, for example using PD1 as interrupt pin:
PORTD.INT0MASK = 0x04; // PD2 is the source of interrupt for INT0.
PORTD.INT1MASK = 0x02; // PD1 is the source of interrupt for INT1.
PORTD.INTCTRL = 0x0F; // Enable INT1, enable INT0 and place them a high-priority level.
PORTD.PIN2CTRL = 0x03; // configure PD2 pin to interrupt on the low level of signal.PORTD.PIN1CTRL = 0x03; // configure PD1 pin to interrupt on the low level of signal.
Every port has 2 interrupts. You can use more ports if you need more interrupts than 2. You can connect the third switch to a second port and use the INT0 there.
How about polling input(s) from your code, in a loop or from timer interrupt routine(s)? This way you can handle as many input signals as you have inputs capable of sensing the signal change.
The limiting factor, though is the frequency of polling and the delay the polling software introduces.
Of course I assume you want to observe high/low levels of the signal. For more elaborate signal sensing (rising, fallsing, frequency change) the use of ADC is unavoidable.
I hope this helped.

Set-up interruption flag whenever I want

I have a problem with set-up interruption flag in AVR AT90S2313. Normally interruption is setting-up through hardware counter. I want to setting this flag in programming way when I want (at the specific moment). I'm writing all code in C:
SEI(); //enable globall interupt
TIMSK | = (1<<TOIE1); //enable interrupt from timer 1
TIFR | = (1<<TOV1); //enable interruption (setting bit) - IT DOESN"T WORKS!
So, in the last line it should be programming interruption but nothing is happening and I don't know why. Any idea? Thanks in advance.
TIFR registers are special in that writing a 1 to a bit sets it to 0.
Edit in response to a comment:
You shouldn't be doing anything with the register as far as I can tell from what little information you have supplied. That is, don't try to use the interrupt mechanism to run the handler. At the point in your code where you want to trigger the interrupt, just call the handler yourself. You may also want to be adjusting the enable bits or clearing flags at the same time -- I don't know what you are trying to do.
If you want the handler to run as if it were acting in response to an interrupt, then you will want to disabled interrupts first. The usual way to do this is
void function_to_trigger_handler()
{
uint8_t sreg = SREG;
cli();
my_interrupt_handler();
SREG = sreg;
}

Resources