ISR on Serial1 Receive help

Status
Not open for further replies.

Steve01

Active member
I'm trying to find documentation on how to setup an ISR for receiving data on the Serial1 USART.
The information on http://www.pjrc.com/teensy/interrupts.html#names left me hanging. I tried importing the header files listed and setup the ISR function but the compile stopped with an error. (The error was looking for more header files)
Is there a good example on setting up an interrupt to handle received data on UART1?

Thank you in advance,
Steve
 
Teensy has ready to use support for all UARTs on Teensy 2 & Teensy 3.
On Teensy 3,
Serial is the USB-to-serial
Seria1 is the first UART
Serial2 is the second
Serial3 is the third
and so on

so just use
Serial1.begin(baudrateDesired)
and use the same procedures for all as you do for Serial. Such as Serial1.print("hello world");
Or same for input from Serial1.
 
Thanks stevech but I must have not worded my request properly. I have the serial working perfect and would like to use an interrupt to catch the incoming data instead of polling for received data. Is there an example program that you know of that I can work with.
I'm using the Teensy 3.1 and Serial1.
 
Add a subroutine outside of your class library. Just remember, initially your ISR will not have access to your local class data. So you must add a pointer to it before the ISR can access it. See the PulsePosition library for an example. Then for the names of the ISR, you can find the names of all the ISR's at the very end of mk20dx128.h file. For UART-1, I see the following, however it appears they are 0-based numbers, and yours above I think are 1-based. So just in case, here's the names of both:

extern void uart0_lon_isr(void);
extern void uart0_status_isr(void);
extern void uart0_error_isr(void);
extern void uart1_status_isr(void);
extern void uart1_error_isr(void);
 
I tried the SerialEvent() and yes stevech you are correct, it didn't work with 3.1. I followed the directions on PJRC's site describing interrupts and get an error when I compile that says, "Expected contructor or type conversion". It was pointing at the "ISR" method.
Here is the code I put together after reading the interrupt page:
#include <avr/interrupt.h>
#include <avr/io.h>

void setup()
{
Serial.begin(9600);
sei();
}

void loop()
{
delay(500);
}

ISR(TIMER0_OVF_vect)
{
Serial.println("Timer");
}


I have read so many documents on interrupts and can't seem to find any that clearly define how it is done. Some include the "MK20DX128.h" (Do I need this header?) file and some don't. Most of the posts say what the problem is but there is never a straight answer on the on how to make the interrupts work. Some set the flags and some don't.
I must be missing something or interrupts are very difficult if you have never done them.
 
If it were me, I would look at the hardware serial sources as an example of how to do this.

I am using tablet. But I believe that it is in the teensy 3 subdirectory as Serial1.c...
 
There's already a ring-buffered interrupt handler for all the UARTs. Serial1, 2, 3.
Can't you just take the library source code for that handler and add a SerialEvent() or your own limited equivalent to that. Starting with bare metal ISR isn't needed.
 
Looking over the Arduino sources, it is not hard to emulate the SerialEvent code base. Personally I don't think it helps much:
There main with this looks like:
Code:
int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    
	for (;;) {
		loop();
		if (serialEventRun) serialEventRun();
	}
        
	return 0;
}
And SerialEventRuns is simply:
Code:
void serialEventRun(void)
{
#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implemented
  if (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implemented
  if (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implemented
  if (Serial3.available()) serialEvent3();
#endif
}
So to emulate in your own code, you can either put something at the start or end of your loop function that simply does:
Code:
if (Serial1.available() SerialEvent1();
So it is more or less simply polling.
 
Thanks stevech but I must have not worded my request properly. I have the serial working perfect and would like to use an interrupt to catch the incoming data instead of polling for received data. Is there an example program that you know of that I can work with.
I'm using the Teensy 3.1 and Serial1.

I wrote a library that does this using dma. I also added readBytesUntil event, Serial1 only so far.

It's still being developed so if you try it out and find an issue let me know.
 
duff, thank you so much for this library.
Here is what I have:
Two Teensy 3.1's connected to each other by two RS485 boards using Serial1. I know this setup was working because I was using a standard send/receive method with poling and was able to communicate back and forth.
I loaded your unmodified sketch on both boards. The first (receiving USB data) Teensy turns the onboard LED on/off each time I send a packet. (perfect) The second Teensy (that only has Serial1 input) does nothing. (Meaning the LED never turns on indicating that the Serial1 port never received any data) I tried commenting out the loop back and had the same result. Any ideas?
I was expecting that the receiving Teensy's LED would come on when the data was received. I should also mention that I am using the "ReadBytesUntil_Event" sketch.
 
I loaded your unmodified sketch on both boards.
You have to comment out the loopback part or it will not send to the other teensy. It's really only good for testing without having to hook up anything.

I tried commenting out the loop back and had the same result. Any ideas?
Maybe try just connecting the teensy serial1's together without RS485 stuff to make sure you can send and receive. I know this works.

Could you post the code you loaded on both teensy and maybe I can help you out?
 
It is working perfectly now, you are amazing and thank you so much for your time and effort on this library. As you were responding to my post I had reloaded the sketches to be sure they were back to original then I commented out the 'loopback' and they worked perfect. Have a good holiday!
 
good to hear, let me know of any issues.

fyi: I'm still updating it and working out bugs.
 
duff, I added the OctoWS2811 library and now I get an error when compiliing. The error is SerialEvent.cpp:207: multiple definition of `dma_ch3_isr'
Since both libraries are using DMA is it possible to use them at the same time?

#include <OctoWS2811.h>
#include <SerialEvent.h>

//-------------Beginning OctoWS2811---------------------
const int ledsPerStrip = 320;

DMAMEM int displayMemory[ledsPerStrip*6];
int drawingMemory[ledsPerStrip*6];

const int config = WS2811_GRB | WS2811_800kHz;

OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, config);
//-------------End OctoWS2811---------------------------

SerialEvent Event1 = SerialEvent();

/*******************************************************
* when the RX buffer is set to 1, an Event will fire
* for every byte received. If you set the buffer to
* more than 1 it will fire every buffer size bytes.
*******************************************************/
char rx1Buffer[128];

void setup() {
leds.begin();
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(0);
while(!Serial);
//-----------------------------------------------------------------------------------------
//Event1.loopBack = true;// internal loopback set / "default = false"
Event1.port = &Serial1;// set port to Serial1
//Event1.txEventHandler = tx1Event;// event handler Serial1 TX
Event1.rxEventHandler = rx1Event;// event handler Serial1 RX
Event1.rxBuffer = rx1Buffer;// user supplied variable to hold incoming Serial1 data
Event1.rxBufferSize = sizeof(rx1Buffer); // size of the RX buffer
Event1.termCharacter = '\n';// this termination character will fire the RX event handler
Event1.begin(9600);// start serial port
//-----------------------------------------------------------------------------------------
}
void loop() {

}

void rx1Event(void) {
// RX Event function prints the buffer when it is full
//char myByte = rx1Buffer[0];
Serial.printf("Termination Character Event: %s\n", rx1Buffer);
//Serial.printf("Byte Recevied Event: %c\n", myByte);
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
 
no they can't since they both use the same dma channels. Thats why I'm interested in this thread, maybe someday we can register what dma channels we need so conflicts like this don't happen.

That being said, are you using teensy 3.1? if so after the new teensduino release maybe you could change my rx, tx dma stuff from channel 1, 2, 3 to channel 4, 5, 6. I could help with this but it would be custom library for you since I want my library to work with T3.0 that doesn't have the extra dma slots that the T3.1 has.

If your using T3.0 you have to use the core serial1 instead.
 
I am using the 3.1 and only Serial1. I'm not sure if the dma_ch3_isr is for Serial3 or not but if so maybe I could just remove that part of the code.
 
I am using the 3.1 and only Serial1. I'm not sure if the dma_ch3_isr is for Serial3 or not but if so maybe I could just remove that part of the code.

it might compile but won't work because the problem is that my library uses dma channel 1 for receiving serial1 data and the OctoWS2811 uses dma channel 1 for something different. So basically in your code SerialEvent will wipe out any dma config that the OctoWS2811 needs. Thats why you would have to change SerialEvent's RX dma channel to something like 4, but I don't think the latest stable release of teensy core (1.18) has those other dma channels register defined yet.

So the simple answer would be No, there not compatible, but I'll look into this later maybe I can come up with something that would work for you.

do you know if i can use the
OctoWS2811 library without any hardware?
 
Status
Not open for further replies.
Back
Top