friendofmegaman wrote:rvan wrote:With my simple testing code (as follows) I think it was the ISR being called which took too many clock cycles (I recall reading 10 cycles of overhead somewhere). Getting away from the Arduino code will hopefully reduce this.
Let us know the results, because in theory I don't see how this is faster. The Arduino sketch is merely a wrapper for what you've written. It puts contents of setup() to main() and the contents of loop() inside the for(;;) loop in main. Of course I might be wrong
It's not the wrapper part of the Arduino environment which is the concern, but rather the Arduino/TeensyDuino library functions, which are known to be inefficient in some respects. I suspect that using attachInterrupt may add additional complexity to the way in which interrupts are actually handled, which consumes unnecessary clock cycles. This is just a guess, though.
friendofmegaman wrote:There's one more concern though. What if a signal arrives while Teensy is handling the previous interrupt? This may me the reason why rvan's attempt didn't succeed. But I'd really like to see the code in order to avoid wasting time on re-doing something that has been done already.
Based on the simple sample program I wrote (see above), I think the issue is simply that the ISR is not being called every time it should, as the interrupting signal (Clock) is too fast; i.e., the ISR cannot be called and return within ~24 clock cycles.
friendofmegaman wrote:Then you need to check the pseudonym for your serial devise where Teensy is. For *nix systems it should be something like /dev/tty.usbXXXX where XXXX is some string. I've no clue how it's addressed in Windows though.
Incedentally, mine is /dev/ttyACM0, not /dev/tty.usbXXXX, in case anyone else is looking for the right device.
friendofmegaman wrote:Another question is has anybody benchmarked the USB serial speed of Teensy 3.1? According to this page: http://www.pjrc.com/teensy/usb_serial.html it is not very big and we need to keep data to transmit as small as possible as I'm trying to do by packing it into an unsigned char array.
The page you linked seems to be for the older Teensy boards, not Teensy 3.1. The older boards are a different architecture, so this information isn't relevant to us. While it may be worth benchmarking serial at some point, I do not suspect it will be a major issue, and think we should work on getting data into the Teensy, before we go into the particulars of how we get it out of the Teensy.
Jazzmarazz wrote:rvan wrote:I had a think about this, and I think the only foolproof way is to store only three pixels per byte and use the remaining two bits to store new line and/or new frame markers. Another option would be to simply count pixels (assuming we always begin sending at the start of a frame) and hope we don't drop any bytes, but that is not as robust.
I like that, 3 pixels per byte and a 2-bit marker. Serial is sure fast enough to handle that.
I imagine the data scheme looking like this:
[hd][px][px][px]
Where hd is a two-bit header, and px is a two-bit pixel.
Pixels are encoded left to right, most significant to least significant.
Possible hd values are:
01 Beginning of line
10 Beginning of frame
11 Reserved
Since 160%3=1, we will have one byte at the end of the line which contains only one pixel. We can probably simply ignore the other two pixel spaces in this byte, without not needing a special header here (note that this byte will directly precede the byte with a newline header).
friendofmegaman wrote:Conjecture:
I'm missing bits because the CLOCK handler for the previous interrupt hasn't finished executing.
Yes. I am quite certain now that this is the case. I had figured that 24 cycles would be enough to set a variable within an ISR, but it seems like it is not. My testing code (p. 3), and yours (p. 5) both point to this.
-----------------------------
Here is the original code I wrote using interrupts. While this does not work on the Teensy (at least at present), I suspect that this strategy would work on a faster board.
/* Author: rvan
Interrupt-based reading of pixel data from the DMG.
This code currently DOES NOT WORK; we suspect this is because the ISRs
(specifically clock_ISR()) are not returning fast enough. Additionally, the
code has been modified for clarity since last being tested, it is possible
that some minor errors have been introduced.
*/
#include <WProgram.h>
#define CLOCK_PIN 23
#define HSYNC_PIN 22
#define VSYNC_PIN 21
unsigned int i;
volatile unsigned char new_pixel = 0;
volatile bool have_pixel = false;
unsigned char three_pixels = 0;
unsigned char num_pixels = 0;
volatile unsigned char place_in_line = 0;
unsigned char line[54];
void clock_ISR() {
/* Read a pixel */
//Do something here to wait for the pixel inputs to settle, if necessary.
new_pixel = PIND;
have_pixel = true;
}
void vsync_ISR() {
/* The vsync_ISR() routine is NOT TESTED. */
/* Note: It may be a bad idea to do serial transfer in the ISR, but we
leave it here for now to eliminate checking more flags in the work loop.
*/
/*
Note also that the new frame and new line markers do not conform to the
protocol described; in reality the remaining six bits would also contain
pixel data.
*/
Serial.write(B100000); //New frame.
}
void hsync_ISR() {
Serial.write(B010000); //New line.
place_in_line = 0;
}
int main() {
DDRD = B00000000; //All pins as input.
pinMode(CLOCK_PIN, INPUT);
attachInterrupt(CLOCK_PIN, clock_ISR, FALLING);
pinMode(HSYNC_PIN, INPUT);
attachInterrupt(HSYNC_PIN, hsync_ISR, FALLING);
pinMode(VSYNC_PIN, INPUT);
attachInterrupt(VSYNC_PIN, vsync_ISR, FALLING);
Serial.begin(1); //Always runs at Full Speed, the parameter is ignored.
for(;;) {
if(have_pixel) {
//Shift the pixels he have two bits to the left, zero the two bits
//where the new pixel goes,
//and OR everything together.
//We assume (for now) that the new pixel is in the two LSBs itself
//and doesn't need shifting.
three_pixels = (three_pixels << 2) | (new_pixel & 3);
have_pixel = false;
num_pixels++;
if(num_pixels == 3) {
/* We store only 3 pixels. This is so we can use the remaining
two bits to show where a frame starts.
*/
//Add the pixel to the line.
line[place_in_line++] = three_pixels;
if(place_in_line == 40) {
//Send the line.
Serial.write(line, 40);
place_in_line = 0; //We shouldn't need this, as
//place_in_line is reset by the hsync ISR.
}
num_pixels = 0;
}
}
}
}
Despite our lack of success so far, it seems like we are making progress, and at least coming to a better understanding of the hardware (and software) involved (I am, at least).