I am developing an application on a Nucleo-144 STM32F439ZI development board (product page, manual) and ran into an issue with hardware interrupts.
The reason I am posting this here instead of the electronic engineering site is that it seems to be a software problem related to the Arduino SDK rather than a hardware problem.
Anyway, when ethernet is off, the code below works meaning the interrupt routine gets triggered:
void setup(){
// ...
// set the user button pin as input
pinMode(PC13, INPUT_PULLDOWN);
// attach an interrupt
attachInterrupt(digitalPinToInterrupt(PC13), interruptHandler, RISING);
// ...
}
The interruptHandler function toggles a led, 3 lines of code. The PB7 pin is set as output within setup().
void interruptHandler(){
digitalWrite(PB7, HIGH);
delay(1000);
digitalWrite(PB7, LOW);
}
However, when using ethernet, it does not:
void setup(){
// ...
// set the user button pin as input
pinMode(PC13, INPUT_PULLDOWN);
//attach an interrupt
attachInterrupt(digitalPinToInterrupt(PC13), interruptHandler, RISING);
// mac and IP are unique on the network
Ethernet.begin(mac, ip);
// give the stack some time to do its business
delay(1000);
// ...
}
In this scenario pressing the button doesn't do anything, the interruptHandler no longer gets triggered.
I'd very much like to use interrupts rather than polling pins.
Am I doing something wrong?
Related
I am having a bit of trouble reading an NFC card with an ESP32 (using Arduino IDE). I'm using PN532 module, which works pretty well. So far my code looks like:
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532.h>
#include <NfcAdapter.h>
PN532_SPI pn532spi(SPI, SS);
NfcAdapter nfc = NfcAdapter(pn532spi);
void setup(void) {
Serial.begin(115200);
Serial.println("NDEF Reader");
nfc.begin();
}
void loop(void) {
//Serial.println("\nScan a NFC tag\n");
if (! nfc.tagPresent())
{
return;}
else{
NfcTag tag = nfc.read();
String scannedUID = tag.getUidString();
Serial.println(scannedUID);
}
delay(5000);
}
which is basically just the example from don's ndef library. I just got the UID string, rather than printing all details of the card.
It does work and displays the UID. However, I get a message saying "Tag is not NDEF formatted". Which I don't really care about. I only want to print the UID to serial and then pick this up in a C# windows app. I guess I could just ignore it, but is there a way to stop it showing up?
Is there a better library I should be using?
Thanks
Andrew
I fixed it by modifying the mifareclassic.cpp file which is part of the library. I just commented out the offending line. Probably a better way since it's still doing the check. But will do for now.
Thanks
Andrew
I am using MPU9250-breakout board with Arduino Uno.
The library I used is from here.
Below is my code.
#include <Arduino_FreeRTOS.h>
#include "mpu9250.h"
MPU9250 IMU(Wire,0x68);
int status;
void task_1(void *pvParameters)
{
(void) pvParameters;
for (;;)
{
}
}
void task_2(void *pvParameters)
{
(void) pvParameters;
for (;;)
{
}
}
void setup() {
Serial.begin(115200);
while(!Serial) {}
status = IMU.begin();
if (status < 0) {
Serial.println("IMU initialization unsuccessful");
Serial.println("Check IMU wiring or try cycling power");
Serial.print("Status: ");
Serial.println(status);
while(1) {}
}
xTaskCreate(
task_2,
(const portCHAR *)"task2", // A name just for humans
128, // Stack size
NULL,
1, // priority
NULL);
xTaskCreate(
task_1,
(const portCHAR *)"task1", // A name just for humans
128, // Stack size
NULL,
1, // priority
NULL);
}
void loop()
{
}
The problem is that when there are two tasks defined, the program will be restarted automatically. But when I comment out task_1, the program works fine. The result value of xTaskCreate is correct.
I guess the problem might be the stack or heap size is too small, but I've increased stack and heap size and it's still doesn't work.
Can anyone tell me where the problem might be from?
At the end of your setup(), you need to start the scheduler:
// Now the task scheduler, which takes over control of scheduling individual tasks, //is automatically started.
vTaskStartScheduler();
That is all I see different between my project which works and yours.
Once you have created your tasks, you have to start scheduler.
Call vTaskStartScheduler() before exiting setup function and after you have created your tasks.
https://www.freertos.org/a00132.html
Just for the info, Arduino-UNO (with ATMega-328P) has very limited RAM and it may happen some tasks won't be created. Check return value of xTaskCreate functions.
When I run into this problem, it's usually been that my interrupt vectors weren't pointing to appropriate handlers. So when the RTOS needed to do a context switch, for example, it jumped off into la-la land. Since you say that taking out the tasks allows it to run to the library call, but fails in the same way, it is possible none of your handlers are setup correctly.
The FreeRTOS website has an FAQ about getting new projects to run that I would suggest reading through to help troubleshoot this kind of problem:
https://www.freertos.org/FAQHelp.html#faq
You might also look at some of the other AVR examples included with FreeRTOS to see how they have interrupts setup: https://www.freertos.org/a00090.html#ATMEL
I´m facing a problem with an application in Arduino Uno.
The board has a sensor that its counting products every second, after some time it sends the number of products to the server however this process takes more than a second, so the code that it is registering the products is not called until this process is completed so a piece of product sometimes is not counted.
I´ve been looking if Arduino supports multi-threading in order to have a thread for sending data to the server and the other one for registering the number of products, but i have no clear answer so far.
What would be the best solution to face this problem?
const long MAX_ITERATION = 100000;
const int OFF = 1;
const int ON = 0;
const int PHOTOELECTRIC_SENSOR = 3;
int counter = 0;
long iteration = 0;
int state = OFF;
void loop() {
registerProduct();
if (iteration >= MAX_ITERATION) {
// this process takes more than a second
sendDataToServer();
iteration = 0;
}
iteration++;
}
void registerProduct() {
int currentSensorState = digitalRead(PHOTOELECTRIC_SENSOR);
if (currentSensorState != state) {
if (currentSensorState == ON) {
counter++;
}
}
state = currentSensorState;
}
void sendDataToServer() {
// Sends data through HTTP protocol, and sets counter to zero
}
It looks like you might want to redesign this. While you might want to use something like threading on a desktop platform you don't have any hardware support for concurrency in that manner on the Arduino UNO. You do however have interrupts which you can use for your current problem.
Put the sensor on a pin change interrupt. Increment the counter in the ISR for that pin change interrupt. Arduino UNO has a few general purpose pin change interrupts, look at the datasheet for more info.
Then create a timer by using one of the internal timers. Attach this to an interrupt, when the timer interrupt fires take the counter amount and then put this aside. You will need to then send that value over to the server. Try to make the send not block. You may need to service the send in the main loop over multiple loop cycles.
By using the interrupts, especially the timing ones, you will free up a lot of processor cycles. Try to keep the amount of code in each of the ISRs as minimal as possible so that you don't lose data from interrupts being missed.
There is no concurrency in the microcontroller hardware or the language.
The correct way to do this is use an interrupt to accept the updates form the sensor asynchronously.
You should also not block on the send, you should send a few bytes and then send a few more on every loop through.
Using interrupts would be the preferred method, but you can also get away with using a simple or timed scheduler.
I've been working on a project that required one a while ago and you can find the source code here. It's based on a more extensive queuing library by Zuph called AVRQueue.
A simple implementation of the Scheduler library. I originally wrote it to be compiled with an avr-c compiler and haven't testing it with the arduino IDE but it shouldn't be an issue.
Scheduler m();
void setup() {
m.addTask(querySensor, "q_sens", 0, 1000);
m.addTask(doStuffWithData, "stuff", 0, 5000);
}
void loop() {
m.run(millis());
}
int querySensor(unsigned long now) {
...
}
int doStuffWithData(unsigned long now) {
...
}
I have a qt program. I have CAN requests that I want to send in sequential order.
I want to wait for answers, before sending other requests.
SendReadLatchCommand(fam,prod,addr,0x00000000, 4); // 1st request
// wait for answer and analyze it??
SendReadLatchCommand(fam,prod,addr,0x00000002, 4); // 2nd request
I have a receiveData() method, called by my thread of reception, where I save the received message.
I want to sleep in my main program and we awake when receiving answer.
I can't use signal/slot because in the slot, I don't know what is the last request I sent, so I can't continue emitting requests.
How can I do this?
thanks
If i understand you properly, you wanted to process the request synchronously.
Look into the QEventLoop in the qtdoc, you can do it this way:
QEventLoop wait_loop;
// 1st request
connect(request_1, SIGNAL(sig_answer_arrived()), &wait_loop, SLOT(quit()));
request_1->send_request();
wait_loop.exec();
// here we already got the answer
analyze_answer();
// the 2nd request does the same
I'm not sure whether it is a good idea to block your main thread, however it can be done by using a binary semaphore, which is the same as a counting semaphore with a maxCount of 1. Therefore one can use a counting semaphore QSemaphore
Typically, a QSemaphore is implemented in terms of QWaitCondition (refer Qt help). One could block on a wait condition until the CAN thread signals the wait condition. One can hide the blocking on the wait behind some interface e.g:
//--- Very simple implementation - concept only
QWaitCondition cond_;
QMutex mutex_;
void rxThreadHandler( /*args*/ )
{
while( !quitCalled() )
{
waitOnReceivedData();//Blocks, I assume...
handleReceivedData();
answerRxd();
}
}
void answerRxd()
{
QMutexLocker lock( mutex_ );
cond_.wakeAll();
}
void sendNext( const Buffer& buffer )
{
QMutexLocker guard( mutex_ );
//Waits/Blocks until condition signalled, then locks mutex
// to prevent further signalling (might block rx thread)
cond_.wait( lock.mutex() );
//Unlocking mutex explicitly to allow receipt of data
guard.unlock();
//Now send as result of previous receive. This does not
// prevent receiving thread...
sendNextImpl( const Buffer& buffer );
}
I've researched a bit, and I've ran into a couple of examples of how buttons are used as interrupts. However, the design I'm trying to implement uses analog sensors. Right now, what I want to do is to have my analog sensors flag a boolean to tell the interrupt to execute, not a button. How would I do so?
This is what I have thought up based on what I researched:
boolean isWall;
attachInterrupt(isWall, interruptFunction, RISING);
void loop() {
if(analogSensor.response > 450) {
isWall = true;
}
normalExecution(); // what it normally does if isWall is false
}
void interruptFunction() {
// code implementation
isWall = false; // set isWall back to false after executing interruptFunction
}
void normalExecution() {
// foo
}
Can someone verify?
Perhaps I am completely wrong but it has always been my understanding that interrupts in Arduino are based on the voltage seen by a pin - i.e. they are hardware interrupts. Consequently, while your code is correct for a hardware interrupt, it will not work for a change in a variable.
That said, this link and this link discuss Analog Comparator methods for accomplishing what you are trying to do.