Values initialized and set outside interrupt are zero within interrupt C++ on Xilinx Zynq - c++

I am experiencing a rather odd issue with my code where I have a value that I initialize in the main. Once I try to call that variable inside an interrupt it is 0. What am I missing here? Do different variables live within an interrupt?
I would like to note that this is a more theoretical question about interrupts and whether I can not share values between idle and interrupts.
Supervisor supervisor;
XScuTimer TimerInstance;
XScuGic IntcInstance;
uint32_t offset;
void interruptRoutine(void *CallBackRef) {
// Define pointer to timer
XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
// If timer is expired, clear interrupt status
if (XScuTimer_IsExpired(TimerInstancePtr)) {
XScuTimer_ClearInterruptStatus(TimerInstancePtr);
// Why is offset 0 within the interrupt routine?
xil_printf("Interrupt: %u\n", offset);
}
}
//.. I omitted the interrupt init method ..//
int main() {
while (true) {
// Get all sensor data
offset = 1;
}
}

Related

detached std::thread on esp32 arduino sometimes blocks, sometimes doesn't

I have some code running on ESP32 microcontroller with arduino core,
In the setup() function I wish to have some code threadPressureCalib run independently in its own thread, so I do the following:
std::unique_ptr<std::thread> sensorCalib;
void setup()
{
sensorCalib.reset(new std::thread(threadPressureCalib));
std::thread* pc = sensorCalib.get();
pc->detach();
}
void loop()
{
...
}
Then, I define threadPressureCalib() as follows:
void threadPressureCalib()
{
float pressure=0;
int count;
for(timestarted = millis();(millis()-timestarted) < 10000;)
{ // THIS ONE BLOCKS SETUP() AND LOOP() CODE EXECUTION
Serial.println("Doing things");
}
Serial.println("Doing other things");
for (count=1; count<= 5;count++)
{ //THIS ONE DOES NOT BLOCK SETUP() and LOOP()
float temp;
while(!timer2.Delay(2000)); //Not sure if this is blocking anything
do{
temp = adc_pressure();
}while(temp>104.0 || temp<70.0); //Catch errors
pressure += temp;
}
changeSetting(pressure/5.0);
return;
}
Problem: During the first for loop, the setup() function's execution is stopped (as well as loop())
During the second for loop, nothing is stopped and the rest of the code runs in parallel (as expected)
Why is it that the first half of this code blocks, and then the second half does not?
Sorry if the question is vague or improperly asked, my first q here.
Explanation of timer2 per request in comments:
timer2 is a custom timer class, timer2.Delay(TIMEOUT) stores timestamp the first time it's called and returns false on every subsequent call until the current time = TIMEOUT, then it returns true and resets itself
NonBlockDelay timer2;
//time delay function (time in seconds to delay)
// Set iTimeout to current millis plus milliseconds to wait for
/**
* Called with milliseconds to delay.
* Return true if timer expired
*
*/
//Borrowed from someone on StackOverflow...
bool NonBlockDelay::Delay (unsigned long t)
{
if(TimingActive)
{
if((millis() >iTimeout)){
TimingActive = 0;
return(1);
}
return(0);
}
iTimeout = millis() + t;
TimingActive = 1;
return(0);
};
// returns true if timer expired
bool NonBlockDelay::Timeout (void)
{
if(TimingActive){
if((millis() >iTimeout)){
TimingActive = 0;
iTimeout = 0;
return(1);
}
}
return(false);
}
// Returns the current timeout value in milliseconds
unsigned long NonBlockDelay::Time(void)
{
return iTimeout;
}
There is not enough information here to tell you the answer but it seems that you have no idea what you are doing.
std::unique_ptr<std::thread> sensorCalib;
void setup(){
sensorCalib.reset(new std::thread(threadPressureCalib));
std::thread* pc = sensorCalib.get();
pc->detach();
}
So here you store a new thread that executes threadPressureCalib then immediately detach it. Once the thread is detached the instance std::thread no longer manages it. So what's the point of even having std::unique_ptr<std::thread> sensorCalib; in the first place if it literally does nothing? Do you realize that normally you need to join the thread if you wish to wait till it's completion? Could it be that you just start a bunch of instances of these threadPressureCalib - as you probably don't verify that they finished execution - and they interfere with each other?

Hard Fault When Disabling Timer?

I am trying to get a pulse of 100us to occur 4 times a second through GPIO. The way I am doing this is by having two timer-based interrupts; one that triggers 4 times every second, and another that gets triggered 100us after the first.
Within the interrupt handler of the first timer, the target pin is set high, the second timer is reset, and interrupts on the second timer are enabled. Within the second interrupt handler, the target pin is set low and interrupts are disabled. Here is what my code looks like:
First timer's ISR:
void TIM4_IRQHandler(void)
{
{
TIM4 -> SR = ~(TIM_SR_UIF); // clear UIF flag
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_HIGH); // target pin
endTrigger->restartTimer();
endTrigger->enableInterrupts();
}
}
Second Timer's ISR:
void TIM5_IRQHandler(void)
{
{
TIM5 -> SR = ~(TIM_SR_UIF); // clear UIF flag
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, GPIO_LOW); // target pin
endTrigger->disableInterrupts();
}
}
retart timer function:
void Timer::restartTimer() {
myhTim->CR1 &= ~TIM_CR1_CEN; // disable the timer
myhTim->CNT = 0; // reset count
myhTim->SR = 0; // clear any interrupt flags
myhTim->CR1 = TIM_CR1_CEN; // re-engage timer
}
For whatever reason, the second I write to CR1 I get a hard fault... Any idea why? I am aware that there are other approaches to getting a 100us pulse but this seemed to be the simplest way for what our needs are... We aren't going to need the additional timer and we will need to be semi-frequently syncing the pulse to an external piece of hardware.
The timer interrupt occurred immediately after initializing the first timer. I had to add a line of code to my second IRQ such that it would only attempt to monkey with the second timer in the case of it not being a nullptr.

C++ variable changed during interrupt resets after interrupt

I'm trying to use a flag to see if an event has finished.
Via the debugger, I have seen that the interrupt triggers correctly and does set the value of transmitCompleteI2c to 1. When I return to the if statement which checks whether or not the flag has been set to 1, it has been reset to 0.
The only 2 locations where i alter the value of transmitCompleteI2c are after the if statement and in the interrupt routine.
I'm running the following bits of code. The declaration of transmitCompleteI2c is done in the header file of the class. fireEvent() is a member function of the class I2c.
volatile uint8_t transmitCompleteI2c;
void I2c::foo() {
if (transmitCompleteI2c) {
transmitCompleteI2c = 0;
// trigger event which sets transmitComplete back to 0 when done
fireEvent();
}
}
void I2c::sendHandler(XIic *InstancePtr) {
transmitCompleteI2c = 1;
}
After some extensive digging, it turned out that the address the interrupt routine writes a transmitCompleteI2c to is not the same as the variable in the class. Even after renaming the variable, it is still happening. Below are the header file and source code of my class.
Header file:
#define SLAVE_ADDRESS 0xA0/2
#define SEND_COUNT 16
#define RECEIVE_COUNT 16
#define IIC_INTR_ID XPAR_FABRIC_AXI_IIC_0_IIC2INTC_IRPT_INTR
#define IIC_DEVICE_ID XPAR_AXI_IIC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
class I2c{
private:
void sendHandler(void* InstancePtr, int);
void receiveHandler(XIic* InstancePtr, int);
void statusHandler(XIic* InstancePtr, int);
XIic_Config* configPtr;
const XScuGic& intcInterrupt;
XIic iicDevice;
int status;
uint8_t writeBuffer[SEND_COUNT];
uint8_t readBuffer[RECEIVE_COUNT];
volatile uint8_t transmitCompleteI2c, receiveComplete;
volatile bool test;
public:
I2c() : intcInterrupt{IntcInstance} {};
uint8_t initialize();
int writeData(u16 ByteCount);
int readData(u8 *BufferPtr, u16 ByteCount);
};
Implementation:
Initialization function:
uint8_t I2c::initialize() {
// init driver
configPtr = XIic_LookupConfig(IIC_DEVICE_ID);
XIic_CfgInitialize(&iicDevice, configPtr, configPtr->BaseAddress);
//init interrupt system
XScuGic_SetPriorityTriggerType((XScuGic*) &intcInterrupt, IIC_INTR_ID, 0xA0, 0x3);
status = XScuGic_Connect((XScuGic*) &intcInterrupt, IIC_INTR_ID, (Xil_ExceptionHandler) XIic_InterruptHandler, &iicDevice);
XScuGic_Enable((XScuGic*) &intcInterrupt, IIC_INTR_ID);
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler) XScuGic_InterruptHandler, &IntcInstance);
Xil_ExceptionEnable();
// set transmit flag
transmitCompleteI2c = true;
xil_printf("%08x\n", &transmitCompleteI2c);
// attach interrupts to i2c device
XIic_SetSendHandler(&iicDevice, &iicDevice, (XIic_Handler) (&I2c::sendHandler));
XIic_SetRecvHandler(&iicDevice, &iicDevice, (XIic_Handler) &I2c::receiveHandler);
XIic_SetStatusHandler(&iicDevice, &iicDevice, (XIic_StatusHandler) &I2c::statusHandler);
// set slave address
status = XIic_SetAddress(&iicDevice, XII_ADDR_TO_SEND_TYPE, SLAVE_ADDRESS);
// start device
status = XIic_Start(&iicDevice);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
Write data function:
int I2c::writeData(u16 ByteCount) {
xil_printf("%08x\n", &transmitCompleteI2c);
/*
* Set flag
*/
transmitCompleteI2c = false;
/*
* Send the data
*/
status = XIic_MasterSend(&iicDevice, &writeBuffer[0], 6);
if (status != XST_SUCCESS) {
xil_printf("%d\n", status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
Interrupt routine:
void I2c::sendHandler(void *InstancePtr, int byteCount) {
transmitCompleteI2c = true;
xil_printf("%08x\n", &transmitCompleteI2c);
}
"...it should all be in the same class"
but transmitCompleteI2c isn't a static member, so it has to be the same object, not just the same class. Every instance of I2c gets its own copy of each non-static data member.
You can just make it static if you know only one copy is required (this effectively makes it a global, although still only accessible by I2c) - but don't forget it needs a single non-inline definition.
Alternatively, you need to figure out what I2c objects exist, and where they're created. You can implement all constructor and assignment operator overloads with logging (or to set breakpoints) if you're having trouble figuring out where they get created.

One interrupt function to modify a dynamically determined instance?

As usual, I know how to bypass this problem with some ugly patch work, but I want to make it elegant: I would like to make a small wrapper for motors commanded by an Arduino, which would unfortunately mean writing a distinct interrupt routine for each instance of motor because it has to modify the right step counter (member variable of the motor class) to determine its rate. However those functions would obviously have the same processing...
My question is: how can I determine which counter to modify in a unique interrupt routine?
Here is what I have so far, I'd like to hide interrupts from the user.
class Motor {
volatile int counter;
unsigned long lastUpdate; //Last timestamp update (for calculating the rate)
static const unsigned int RESOLUTION = 1024; //Number of steps in one rev
static const unsigned int RPMS_TO_RPM = 60000; //Convers rev/ms to rpm
public:
Motor() : counter(0)
{
lastUpdate = millis();
}
void encoderInput(bool pinA, bool pinB)
{
counter += (pinA ^ pinB)*(-1)+!(pinA ^ pinB);
}
int getRate() {
int ret = float(counter)/RESOLUTION/(millis() - lastUpdate)*RPMS_TO_RPM;
lastUpdate = millis();
counter = 0;
return ret;
}
};
/* Example:
* Motor motor1;
*
* void motor1_isr(void) {
* motor1.encoderInput(PIN_A, PIN_B);
* }
*
* void setup() {
* attachInterrupt(PIN_I, motor1_isr, CHANGE);
* Serial.begin(9600);
* }
*
* void loop() {
* Serial.println(motor1.getRate());
* delay(1000);
* }
*/
Thanks for your help, I think it would be useful to other people as well once it's done with :)
Regards,
Mister Mystère
You are facing a fundamental problem: an ISR is called with no data. In other words, the ISR function is not provided any data that indicates its source of the interrupt.
The basic approach is that the person writing the code provides the linkage between input and action by hardcoding a function. The tricky approach you are looking for is a method by which the ISR can figure out what the source was.
So you want to have N motors with 2N inputs from quadrature encoders. A single interrupt handler is attached to all the input pins on a CHANGE condition. The same handler gets called for all N motors. It can figure out which Motor to update by comparing the input pins to the values the last time it was called. If the input pins changed, then call that motor. Here is a psuedo code
Motor motor1;
Motor motor2;
onSomethingChanged() {
static int in1aprev, in1bprev;
static int in2aprev, in2bprev;
int in1a, in1b;
int in2a, in2b;
in1a = digitalRead(....
same for other in's
if( (in1a!=in1alast) || (in1b!=in1blast)) {
motor1.encoderInput(in1a,in1b);
in1alast = in1a;
in1blast = in1b;
}
if( (in2a!=in2alast) || (in2b!=in1blast)) {
motor2.encoderInput(in2a,in2b);
in1a2ast = in2a;
in1b2ast = in2b;
}
return;
}
Not so long ago this type of function would be handled in an entire chip (see programmable interrupt controller ). The chip implements all the logic to trigger and capture the source of the interrupt. The main CPU just gets a trigger "something happened". The handler polls the chip to ask "what happened".
Having offered this method, I'm not sure I would recommend. You cannot hide what is going on with your code. The motor must be physically wired to the correct pins. You have consumed a scarce resource -- you have to tell people.

Arduino: interrupt expensive function and resume another

As a first project I plan on making a teensyduino ambient light with different light modes, which are checked in a big switch statement - now I want to switch from one mode to another by pressing a button.
googling lead me to using interrupts, but there is one point that is not clear - if I press the button during an expensive function, which takes long time and has many variables in use, what happens if i call the main loop from the interrupt, does the remaining state of remain in the ram and leads to a stackoverflow if I do switch too many times or is it cleared.
Here some code:
const int speed = 30 //milliseconds
const int modes = 11; //maximum number of modes
const int red = 15;
const int green = 14;
const int blue = 12;
volatile int mode = 0;
void setup() {
pinMode(red , OUTPUT);
pinMode(green , OUTPUT);
pinMode(blue , OUTPUT);
randomSeed(analogRead(0));
Serial.begin(9600);
attachInterrupt(0,incMode,CHANGE); // 0 -> digital pin 2
}
void loop() {
switch(mode){
case 0:{
Serial.println("powerdown");
setAll(0);
delay(1000);
break;
}
\\...
case modes:{
\\ expensive long function
}
}
}
void blinkAll(int times){
for(int i=1;i <= times;i++){
setAll(255);
delay(speed*17);
setAll(0);
delay(speed*17);
}
}
void setAll(int bright){
analogWrite(red , bright);
analogWrite(green , bright);
analogWrite(blue , bright);
}
void incMode(){
delay(speed);
blinkAll(2); //to indicate mode has changed
mode = (mode+1) % (modes+1); //switch starts with 0 so use "% modes+1"!
Serial.println("mode increased");
//--> loop();
//--> would resume the main loop but lead to a stackoverflow i presume
}
How would I break out of the running function without delay and stack pollution.
I know I could just set the mode and wait until the function has ended, but if I have a mode that takes minutes to end I want to be able to switch from it immediately.
PS.: Though I am using a teensyduino, I will use the arduino tag, and as I don't know what language the arduinio uses the tags c/c++. Please change this if it is not appropriate.
You would eventually overflow the stack if you were to reenter main from the interrupt handler multiple times recursively. Additionally, since you'll still be in the interrupt handler as far as the hardware is concerned, you'll have all kinds of weirdness - in particular, interrupts are blocked when you're already in an interrupt, which means delay() won't work and millis() won't count up, and various other things will be broken as well unless you figure out some way to manually re-enable interrupts.
A better way to solve this would be to make your 'expensive long function' instead be a state machine driven by a cheap, short function that is called very frequently. Your interrupt handler can then simply set a flag that is checked on entry into this function, at which point the current mode (ie, current state machine) is changed.
This approach also makes it easier to define new lighting modes. For example, you could define something like this:
struct phase {
unsigned char r, g, b, delay;
};
unsigned long t_nextPhase;
volatile struct phase *forceMode = NULL;
struct phase *mode = blinkAll;
int nextPhase = 0;
struct phase blinkAll[] = {
{ 255, 255, 255, 17 },
{ 0, 0, 0, 17 },
{ 0, 0, 0, 255 } // loop sentinel
};
void lighting_kernel() {
noInterrupts(); // ensure we don't race with interrupts
if (forceMode) {
mode = forceMode;
forceMode = NULL;
t_nextPhase = millis();
nextPhase = 0;
}
interrupts();
if (t_nextPhase > millis()) {
return;
}
struct phase *cur_phase;
do {
cur_phase = mode[nextPhase++];
if (cur_phase->delay == 255) {
nextPhase = 0;
}
} while (cur_phase->delay == 255);
analogWrite(red , cur_phase->r);
analogWrite(green , cur_phase->g);
analogWrite(blue , cur_phase->b);
t_nextPhase = millis() + cur_phase->delay;
}
Now to define a new lighting mode you just need a new array of colors and times, rather than writing new code. Adding things like color ramps and other such effects is left as an exercise to the reader.