Communicating dsPIC with PC application through UART. Receiver interrupt handling - interrupt

I'm communicating my C# applications with dsPIC x16 microcontroller using UART. I want to send/receive fixed size frames and I tried to manage it in a following way:
if(readFrame)
{ IEC0bits.U1RXIE=0; //turn off the U1RX interrupts
readFrame = false;
while(indexer < 8 )
{
while(!U1STAbits.URXDA);
modbusBuffer[indexer]=U1RXREG;
indexer++;
}
if(indexer == 8)
{
modbusRecvTask(modbusBuffer);
indexer=0;
}
IEC0bits.U1RXIE=1; //turn on U1RX interrupts
}
void _ISR_NAP _U1RXInterrupt()
{
if(IFS0bits.U1RXIF)
{
IFS0bits.U1RXIF = 0; //set the interrupt flag to false
if(U1STAbits.OERR==1) //check overload error
{
U1STAbits.OERR=0; //clear error flag
}
else
{
readFrame = true;
}
}
}
The thing is that it works fine only for the first received frame. After that the program goes into the receiver interrupt again and sets the flag readFrame to true even though no bytes were send and is getting stuck in line:
while(!U1STAbits.URXDA);
I've read some advices to clear the read buffer of the UART in order to prevent the program to go into the ISR again but I couldn't find a way to do it.

Related

Raspberry Pi Pico locks up when I try to use interrupts

I'm trying to use encoders to track the movement of three wheels on a robot, but as soon as any of the motors move the robot "locks up", it stops responding to commands, stops printing to the serial monitor, and just keeps spinning its wheels until I turn it off. I cut out everything except just the code to track one encoder and tried turning the wheel by hand to sus out the problem, but it still locked up. And even more strangely, now it will start spinning one of the wheels even though I've removed any code that should have it do that, even by mistake.
I used the Arduino IDE to program the pico since I've got no familiarity with python, but I can't find any information or troubleshooting tips for using interrupts with the pico that don't assume you're using micropython.
Here's the simplified code I'm using to try to find the problem. All it's meant to do is keep track of how many steps the encoder has made and print that to the serial monitor every second. Ive tried removing the serial and having it light up LEDs instead but that didn't help.
int encA = 10;
int encB = 11;
int count = 0;
int timer = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(encA),readEncoder,RISING);
timer = millis();
}
void loop() {
// put your main code here, to run repeatedly:
if (timer - millis() > 5000) {
Serial.println(count);
timer = millis();
}
}
void readEncoder() {
int bVal = digitalRead(encB);
if (bVal == 0) {
count--;
}
else{
count++;
}
}
Does the mapping function digitalPinToInterrupt for the Pi Pico work?
Can you try just using the interrupt number that corresponds to the pi?
attachInterrupt(9,readEncoder,RISING); //Or the number 0-25 which maps to that pin
https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html
You have the wrong pin to encoder in your example (maybe you incorrectly copy and pasted)?
attachInterrupt(digitalPinToInterrupt(**encA**),readEncoder,RISING);
void readEncoder() {
int bVal = digitalRead(**encB**); ...}
There is similar code on GitHub that you could modify and try instead.
https://github.com/jumejume1/Arduino/blob/master/ROTARY_ENCODER/ROTARY_ENCODER.ino
It might help you find a solution.
Also,
https://www.arduino.cc/reference/en/libraries/rpi_pico_timerinterrupt/
The interrupt number corresponds to the pin (unless you have reassigned it or disabled it) so for pin 11 the code can be:
attachInterrupt(11, buttonPressed, RISING);
This works:
bool buttonPress = false;
unsigned long buttonTime = 0; // To prevent debounce
void setup() {
Serial.begin(9600);
pinMode(11, INPUT_PULLUP);
attachInterrupt(11, buttonPressed, RISING);
// can be CHANGE or LOW or RISING or FALLING or HIGH
}
void loop() {
if(buttonPress) {
Serial.println(F("Pressed"));
buttonPress= false;
} else {
Serial.println(F("Normal"));
}
delay(250);
}
void buttonPressed() {
//Set timer to work for your loop code time
if (millis() - buttonTime > 250) {
//button press ok
buttonPress= true;
}
buttonTime = millis();
}
See: https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html for disable, enable etc.

How to optimize the code for reading SPI through ARDUINO in SLAVE mode

Not important:
I am doing a project to integrate a bluetooth module into a car radio pioneer. I understand perfectly well that it's easier to buy a new one =) but it's not interesting. At the moment, the byproduct was an adapter on arduino of resistor buttons, which the pioneer did not understand. The same adapter also controls the bluetooth board, it can switch the track forward and backward (there is no button on the steering wheel for pause). Now I want the bluetooth to turn on only in AUX mode. But there is a problem, which mode can be understood only by reading the signal from the SPI bus of the commutation microcircuit. I was able to read this data using arduino nano. I do not have an analyzer, but it is not necessary that I would understand something additional with it.
Essence of the question:
Using the scientific poke method, I found sequences indicating the launch of a particular mode, for example:
10110011
1
111
1000000
I'm sure I'm doing it wrong, but in the meantime I get duplicate results. But, when I try to detect them using IF, the nano speed is not enough and the chip starts to pass data.
#include "SPI.h"
bool flag01, flag02, flag03, flag11, flag12, flag13, flag31, flag32, flag33;
void setup (void)
{
Serial.begin(9600);
pinMode(MISO, OUTPUT);
SPCR |= _BV(SPE);
SPI.attachInterrupt();
}
// Вызываем функцию обработки прерываний по вектору SPI
// STC - Serial Transfer Comlete
ISR(SPI_STC_vect)
{
// Получаем байт из регистра данных SPI
byte c = SPDR;
Serial.println(c, BIN);
if (c == 0b1) {
Serial.println("1 ok");
flag11 = true;
} else {
flag11 = false;
}
if (c == 0b11 && flag11) {
Serial.println("11 ok");
flag12 = true;
} else {
flag12 = false;
flag11 = false;
}
if (c == 0b1100000 && flag11 && flag12) {
Serial.println("1100000 ok");
flag13 = true;
} else {
flag13 = false;
flag12 = false;
flag11 = false;
}
}
void loop(void)
{}
I myself am scared to look at this code, but I cannot think of anything better. It seems like I heard about some kind of buffer, but I don't know how to screw it to this solution. After all, the data packets go with dropping the CS signal and I can’t figure out how to determine the beginning and end of the packet from the commands in order to write it to a buffer or array and only then go through it with a comparison.
I will be grateful if someone will tell me at least in which direction to move.
There is also esp8266, but there is a limitation on the size of a data packet of 32 bits in a slave mode and I do not know how to get around it correctly.
So, actually the question.
How can I optimize the code so that the arduino has time to process the data and I can catch the pattern?
Perhaps, if we implement reading of data of arbitrary length on esp8266, or at least fill them to the required length, it would help me. But I still can't figure it out with the spi.slave library.
First you should keep your ISR as short as possible, certainly don't use Serial print inside the ISR.
Secondly, if you don't know exactly how long the data is, then you need to have a buffer to capture the data and try to determine the data length first before you trying to analysis it.
volatile uint8_t byteCount = 0;
volatile bool dataReady = false;
byte data[32];
// SPI interrupt routine
ISR (SPI_STC_vect)
{
data[byteCount++] = SPDR;
dataReady = true;
}
void setup (void)
{
// your SPI and Serial setup code
}
void loop (void)
{
// for determine the data stream length
if (dataReady) {
Serial.println(byteCount);
dataReady = false;
}
}
Once you know how long the data stream is (let assumed it is 15-byte long), you can then change your sketch slightly to capture the data and analysis it.
volatile uint8_t byteCount = 0;
volatile bool dataReady = false;
byte data[32];
// SPI interrupt routine
ISR (SPI_STC_vect)
{
data[byteCount++] = SPDR;
if (byteCount == 15)
dataReady = true;
}
void loop (void)
{
if (dataReady) {
dataReady = false;
// do your analysis here
}
}

Using performance monitor unit to generate an interrupt on Xilinx ZynqZC706

I am currently trying to use the performance monitor to generate an interrupt when an overflow of Data Cache misses occurs. I have enabled the pmu and the IRQ for the performance monitor (PMINTENSET is 1 for the counter). I am able to see that the overflow flag is set when the overflow occurs but the interrupt is never triggered. I think I am missing something when setting up the interrupt. I am using Xilinx SDK 2018.2.
I have attached my code for setting up the interrupt:
XScuGic xInterruptController; /* Interrupt controller instance */
static void setup_interrupt(void)
{
uint32_t status;
XScuGic_Config *pxGICConfig;
pxGICConfig = XScuGic_LookupConfig( XPAR_SCUGIC_0_DEVICE_ID );
if (pxGICConfig==NULL)
{
xil_printf("\nERROR LOOKING UP CONFIGURATION");
for(;;);
}
status = XScuGic_CfgInitialize( &xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress );
if (status != XST_SUCCESS)
{
xil_printf("\nERROR INITIALIZING CONFIGURATION");
for(;;);
}
status = XScuGic_SelfTest(&xInterruptController);
if (status != XST_SUCCESS)
{
xil_printf("\nERROR: SELF TEST FAILURE");
for(;;);
}
/*
* Initialize the exception table.
*/
Xil_ExceptionInit();
status = RegisterInterruptExceptions(&xInterruptController);
if (status != XST_SUCCESS) {
xil_printf("\nERROR: SetUP Interrupt System Failed");
for(;;);
}
status = XScuGic_Connect( &xInterruptController, XPS_PMU0_INT_ID, (Xil_ExceptionHandler) pmuIRQ_handler, ( void * ) &xInterruptController);
if (status!= XST_SUCCESS)
{
xil_printf("\nERROR CONNECTING INTERRUPT");
for(;;);
}
XScuGic_SetPriorityTriggerType(&xInterruptController, XPS_PMU0_INT_ID, 8, 0b10); // Priority 8 (second highest) and high level sensitivity
XScuGic_InterruptMaptoCpu(&xInterruptController, 0, XPS_PMU0_INT_ID);
// Enable the interrupt for the xTimer in the interrupt controller.
XScuGic_Enable( &xInterruptController, XPS_PMU0_INT_ID );
}
int RegisterInterruptExceptions(XScuGic *XScuGicInstancePtr)
{
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the ARM processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler,XScuGicInstancePtr);
/*
* Enable interrupts in the ARM
*/
Xil_ExceptionEnable();
return XST_SUCCESS;
}
void pmuIRQ_handler( void *CallbackRef )
{
xil_printf("Interrupt occurred\n");
}
I am not sure if I need to use Vivado to map the PMU interrupt to the GIC? I couldn't find any examples on generating interrupts using the performance monitor. I am currently using the default ZC706 HW platform provided by Xilinx SDK and I am not sure if I need to generate a bitstream in Vivado the maps the PMU to the GIC? I thought that this was done by using XScuGic_InterruptMaptoCpu().
I tried with both XPS_PMU0_INT_ID and XPS_PMU1_INT_ID, but neither worked. I tried to follow this post on using shared peripheral interrupts since PMU is this type of interrupt: https://forums.xilinx.com/t5/Processor-System-Design-and-AXI/Using-Private-and-Shared-interrupts-on-Zynq/m-p/773673
Thanks for the help,
Javier
The last parameter is incorrect. It should be 0b01 For high-level sensitivity instead of 0b10, as shown below:
XScuGic_SetPriorityTriggerType(&xInterruptController, XPS_PMU0_INT_ID, 8, 0b01); // Priority 8 (second highest) and high level sensitivity

Cannot transmit every characters through UART

I am using stm32f0 MCU.
I would like to transmit every single byte received from the uart out of the uart. I am enabling an interrupt on every byte received from uart.
My code is quite simple.
uint8_t Rx_data[5];
//Interrupt callback routine
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) //current UART
{
HAL_UART_Transmit(&huart1, &Rx_data[0], 1, 100);
HAL_UART_Receive_IT(&huart1, Rx_data, 1); //activate UART receive interrupt every time on receiving 1 byte
}
}
My PC transmits ASCII 12345678 to stm32. If things work as expected, the PC should be receiving 12345678 back. However, the PC receives 1357 instead. What is wrong with the code?
Reenabling interrupts may be inefficient. With a couple of modifications it is possible to keep the interrupt active without needing to write the handler all over again. See the example below altered from the stm32cubemx generator.
/**
* #brief This function handles USART3 to USART6 global interrupts.
*/
void USART3_6_IRQHandler(void)
{
InterruptGPS(&huart5);
}
void InterruptGPS(UART_HandleTypeDef *huart) {
uint8_t rbyte;
if (huart->Instance != USART5) {
return;
}
/* UART in mode Receiver ---------------------------------------------------*/
if((__HAL_UART_GET_IT(huart, UART_IT_RXNE) == RESET) || (__HAL_UART_GET_IT_SOURCE(huart, UART_IT_RXNE) == RESET)) {
return;
}
rbyte = (uint8_t)(huart->Instance->RDR & (uint8_t)0xff);
__HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
// do your stuff
}
static void init_gps() {
__HAL_UART_ENABLE_IT(&huart5, UART_IT_RXNE);
}
You should make a tx array buffer as well, and use interrupt for writing as well (The first write if not enabled yet, should be sent immediately).
There should be examples of this for STM32 around.
You should probably switch the two lines: Transmit and Receive. The Transmit function waits for a timeout to send the character, in meantime the next received character is missed.

How do I send strings between my osx app and arduino continuously?

I made a cocoa application that generates a list of instructions for an arduino uno to execute. Because the list is too large to fit at one time within the arduino's memory, I am trying to send the arduino an individual instruction at a time.
Arduino:
void setup(){
Serial.begin(9600);
}
void loop(){
if(Serial.available() > 0){
String in = Serial.readString();
delay(10);
Serial.print(in);
}
Serial.print("A");
}
Cocoa App
(Code after the serial port is open and working)
- (void)incomingTextUpdateThread: (NSThread *) parentThread {
// mark that the thread is running
readThreadRunning = TRUE;
const int BUFFER_SIZE = 1;
char byte_buffer[BUFFER_SIZE]; // buffer for holding incoming data
long numBytes=0; // number of bytes read during read
// assign a high priority to this thread
[NSThread setThreadPriority:1.0];
// this will loop unitl the serial port closes
while(TRUE) {
// read() blocks until some data is available or the port is closed
numBytes = read(serialFileDescriptor, byte_buffer, BUFFER_SIZE); // read up to the size of the buffer
if(numBytes>0) {
if(byte_buffer[0] == 'A'){
Coordinate *c = [coordinates objectAtIndex:coordinateIndex];
[self writeString:[self formateCoordinateString:c]];
coordinateIndex++;
}
}
if(coordinateIndex == coordinates.count){
close(serialFileDescriptor);
break;
}
}
readThreadRunning = FALSE;
}
I run the arduino code first and it prints a bunch of 'A's in the serial console. However once I start the cocoa app, it stops printing 'A's and doesn't do anything.
When I set a breakpoint within the while loop, the arduino starts printing the 'A's again. I continue to step within the while loop, and the "instruction" string is sent correctly to the arduino.
My issue is that this only works when I set this break point. Otherwise both my cocoa app and arduino app go into a stand-still.
Thanks for any and all advice! Please feel free to ask for clarification.