Teensy 3.6 VGA driver

I just compiled the ASCIITableVGA with SERIAL: Raw HID - and NO VGA JITTER!!!

THIS PRINTS and runs VGA smoothly. Using TyCommander (and this time the IDE SerMon too) it finds the HID Teensy and is receiving these print commands each time it indexes and prints the new ASCII value to the VGA:
Code:
     Serial.print("ASCII::");
     Serial.println(thisByte);

This gives an easy workaround for DEBUG output on VGA - and does not impact the VGA display.

Same proves true with my prior lines sample using Raw HID to write during each loop:
Code:
  for (col = 0; col < fb_width; col += 18) {
    uvga.drawLine(col, 0, col, fb_height, 0b00011100);
    uvga.drawLine(col + 9, 0, col + 9, fb_height, 0b00000011);
    [B]Serial.print(".");[/B]
  }
[B]  Serial.print("millis::");
  Serial.println(millis());
[/B]

Does the Raw HID do something different? No keep alive messages or something? Does this offer any general solution for USB or USB Host.

<edit>
I set F_BUS to 120 and Spheres text gets left shifted off the screen a few pixels (half the "S") - and then compiling for USB results in a bad device on Win 10 - though it worked when recompiled. Also the Spheres seem to have shifted and are now centered versus F_BUS=60

My Lines Demo compiled with Serial USB runs with much LESS (95% less?) jitter at F_BUS 120 w/ F_CPU=240 - and USB prints still work.
 
Last edited:
Workaround for debug would be to dump to Serial1 and use a second Teensy (with TyCommander) to echo/proxy through the text to another serial window. Though PS2 pins using Serial1 as built so will need to see if another is open. New Teensy64_VGA PCB does present Serial1 pins as ready to use.

I just noticed something in what you say. Does this means you have no problem when using serial[2-5] or even serial1 as long as it is not connected using USB ?
 
I set F_BUS to 120 and Spheres text gets left shifted off the screen a few pixels (half the "S") - and then compiling for USB results in a bad device on Win 10 - though it worked when recompiled. Also the Spheres seem to have shifted and are now centered versus F_BUS=60

Sometimes, I have a similar problem. I just force the monitor to auto-adjust and it fixes the problem.

My Lines Demo compiled with Serial USB runs with much LESS (95% less?) jitter at F_BUS 120 w/ F_CPU=240 - and USB prints still work.

How do you force F_BUS @120MHz ? I though it should not go higher than 60Mhz
 
I pulled up one end each of my two misplaced resistors and crossed them and soldered and it seems good. My first test was VGA to my ~50" TV LCD caveats apply and my color lines looked good. The RED and BROWN colors are so close on 1K and 2K.

I did not actually try Serial# output - that was just conjecture as it uses other hardware. But then as noted I tried RAW_HID and I got debug output over USB with NO JITTER. That is a better step to try first. If you are using TyCommander it is great to use for HID or other - especially if you do ever add a second connected Teensy at the same time as it allows unique sketch to go to specified Teensy - or same sketch to multiple Teensy's - and get a serial output window for each.

Paul - or someone who knows HID versus Serial USB may say better why this simpler/earlier/BIOS supported interface acts differently on USB and doesn't affect VGA DMA and timing - and if the T_3.6 HOST issue Frank is seeing on Teensy64 might work if it only implemented HID and not full USB device protocol.

Ran other sketches at 240==cpu and 120==F_bus with no apparent problem. As noted below - "caveats apply" - but generally it works well and Teensy64 requires it for full C64 emulation.

In Kinetis.h about line 765 - comment the default 60000000 and uncomment as below:
Code:
#if (F_CPU == 240000000)
 #define F_PLL 240000000
 #ifndef F_BUS
 // #define F_BUS 60000000
 //#define F_BUS 80000000   // uncomment these to try peripheral overclocking
 #define F_BUS 120000000  // all the usual overclocking caveats apply...

Try that and maybe you'll see what I saw in Spheres? When going back to 60 there was a left border space the sphere's didn't hit - at 120 they bounced the edges on both sides - but the "S" was split about the middle and repeatable. USB Jitter in lines was not gone at 120=F_bus - but it was greatly reduced - so it seems to help the timing throughput on VGA and USB interaction.
 
About HID versus USB_Serial I found this note on PJRC that could explain the constant disturbance to VGA as the MCU USB core steals bus cycles:

PJRC.com/teensy/td_serial.html
“All USB bandwidth is managed by the host controller chip in your PC or Mac. When a full or partially filled buffer is ready to transmit, it actual transmission occurs when the host controller allows. Usually this host controller chip requests any scheduled transfers 1000 times per second, so typically actual transmission occurs within 0 to 1 ms after the buffer is scheduled to transmit. If other devices are using a lot of USB bandwidth, priority is given to "interrupt" (keyboard, mouse, etc) and "isychronous" (video, audio, etc) type transfers.”
 
HOST: I still wonder WHAt exactly is the cause for the pixel-displacement/flicker. It is about 3 pixel wides which is really a LONG time. But it seems to me, that the beginning of the lines is perfect, and the more it gets to thr right border, the worse it gets. So, there the times are slowly adding.. on the right border it's worst.
And, why the hell there is absolutely no flicker (without host) with device-rawHID - all other device modes (usb0) are flickering
 
Last edited:
I just did a little test on all Serial. When transmittiing data on Serial2 and Serial4, there is no problem, image is perfectly stable. Serial3 is not usable because its pins are used by Red signal. Serial5 produces a very disturbed image, a lot more than when using USB.

IMG_20170927_192019.jpg

The image is so bad than even the first pixel column is not displayed
 
Last edited:
Good news on the serial! Serial #2 with FIFO as always the least hit on interrupts - but then it has that hardware queue which luckily doesn't interfere like the USB hardware does.

I made a crude color test sketch to verify my resistors 'look' like they are proper values in the proper order and firing correctly and it seems they are. It does show flashing on redraw - I want to evolve it one more step and then I'll post it with pics.
 
Quick half an update - my code is improving - but still too ugly no time to share and finish the utility.

I did get this quick pic showing the color gradations in RGB on the bottom row - followed by their complement. One oddity that is apparent is the dark line after the 4th green bar. Code cycles those bars and the bar comes and goes. That same dark area is visible in the top third row after the 4th blue bar - and the same spot on the 2nd row which is a complement of the top row. Some of the other divider lines may have similar artifacts - perhaps this is the monitor scaling - except it isn't top down line?

When the bars shift that darkened area comes and goes and moves around. This is with F_BUS at 120 and F_CPU 240 - not sure if it is the same with F_BUS=60

COLORS.jpg
 
I did get this quick pic showing the color gradations in RGB on the bottom row - followed by their complement. One oddity that is apparent is the dark line after the 4th green bar. Code cycles those bars and the bar comes and goes. That same dark area is visible in the top third row after the 4th blue bar - and the same spot on the 2nd row which is a complement of the top row. Some of the other divider lines may have similar artifacts - perhaps this is the monitor scaling - except it isn't top down line?
View attachment 11642

If you draw your bars using my uVGA functions, maybe you encountered a bug. In uVGA_gfx.cpp, you can try to disable a little optimization by commenting the line
Code:
#define FAST_HLINE
 
Hm. That does not even use DMA ?? Its getting more and more mysterious.

I know. Serial1 and Serial 2 both have 8 bytes FIFO, all other Serial only have 1 byte fifo.

This weekend, I plan to try 2 things. Using a different FTM as Hsync generator, I have seen that FTM0_CH0 uses the same pin as Serial1 RTS (or CTS, can't remember). I will also try to connect an I2C device (either my barometer or an I/O expander) to check if I2C also generates problem.

In the meantime, I prepared a little PCB for the Flexbus version.
Screenshot - 09282017 - 07:54:15 AM.png

Before making it, I still have to check if it technically works and if all components properly fit on the pcb.
 
I commented the FAST_HLINE line out and didn't see a change. Below is the code to see if you see it also and can determine the true source.

I don't know if this proves or shows anything - I just wanted to show color graduations (cmap2[]) to see I had the resistors right - and then played some to see speed and colors.

<edit*3>: added registration triangles to point to edge of screen - showed my monitor needed 'auto adjust' from what it had been showing. Also showed err in final height - updated. Moved bottom row unused space to center to hit both edges.

Code:
// Lines and Color wiring test

#include <uVGA.h>
void yield(void);

#define wait_sync 0
#define wait_beam 0

uVGA uvga;

#define UVGA_DEFAULT_REZ
#include <uVGA_valid_settings.h>

const byte cmap[] =
{
  0b00000000, 0b11100000, 0b11100100, 0b11101000, 0b11101100, 0b11110000, 0b11110100, 0b11111000, 0b11111100,
  0b11011100, 0b10111100, 0b10011100, 0b01111100, 0b01011100, 0b00111100, 0b00011100, 0b00011101, 0b00011110,
  0b00011111, 0b00011011, 0b00010111, 0b00010011, 0b00001111, 0b00001011, 0b00000111, 0b00000011, 0b00100011,
  0b01000011, 0b01100011, 0b10000011, 0b10100011, 0b11000011, 0b11100011, 0b11100010, 0b11100001, 0b11100000, 0b00000000
};
const byte cmap2[] =
{ 0b00000000,
  0b11100000, 0b11000000, 0b10100000, 0b10000000, 0b01100000, 0b01000000, 0b00100000,
  0b00011100, 0b00011000, 0b00010100, 0b00010000, 0b00001100, 0b00001000, 0b00000100,
  0b00000011, 0b00000010, 0b00000001
};

void setup()
{
  int ret;
  ret = uvga.begin(&modeline);
  if (ret != 0)
  {
    Serial.println("fatal error");
    while (1);
  }
}

void loop()
{
  int fb_width, fb_height;
  uvga.get_frame_buffer_size(&fb_width, &fb_height);
  testPrint();
  doLines( fb_width, fb_height, -1 ); // disable draw lines with negative wait on param 3
  if ( 0 || wait_sync ) uvga.waitSync();
  if ( 1 || wait_beam ) uvga.waitBeam();
  // uvga.clear(0);
  // uvga.clear(0b11111111);
  
  // these each take a third of the screen given H and W, Param 3 is bar +/-/0 indexing between draws, Param 4 is time to delay before return
  doCmap( fb_width, fb_height, 2, 0 );
  doPCmap( fb_width, fb_height, -1, 0 );
  doColors( fb_width, fb_height, 1, 0 );
  doRegister( fb_width, fb_height, 1000 );
}

void doCmap( int fb_width, int fb_height, int Nshift, int dtime ) {
  int col;
  static uint16_t pre_adv = 0;
  pre_adv += Nshift;
  uint16_t adv = pre_adv;
  int xx = fb_width / sizeof(cmap);
  int yy = (fb_height - 1) / 3;
  if ( wait_sync ) uvga.waitSync();
  if ( wait_beam ) uvga.waitBeam();
  for (col = 0; col < sizeof(cmap); col++) {
    uvga.fillRect(col * xx, 0, (col * xx) + xx - 1, yy-1, cmap[(col + adv) % sizeof(cmap)]);
  }
  delay( dtime );
}

void doPCmap( int fb_width, int fb_height, int Nshift, int dtime ) {
  int col;
  static uint16_t pre_adv = 0;
  pre_adv += Nshift;
  uint16_t adv = pre_adv;
  int xx = fb_width / sizeof(cmap);
  int yy = (fb_height - 1) / 3;
  if ( wait_sync ) uvga.waitSync();
  if ( wait_beam ) uvga.waitBeam();
  for (col = 0; col < sizeof(cmap); col++) {
    uvga.fillRect(col * xx, yy, (col * xx) + xx - 1, 2 * (yy)-1, 0xff - cmap[(col + adv) % sizeof(cmap)]);
  }
  delay( dtime );
}


void doColors( int fb_width, int fb_height, int Nshift, int dtime ) {
  int col;
  static uint16_t pre_adv = 0;
  pre_adv += Nshift;
  uint16_t adv = pre_adv;
  int yy = (fb_height - 1) / 3;
  int xx = fb_width / (sizeof(cmap2) * 2);

  if ( wait_sync ) uvga.waitSync();
  if ( wait_beam ) uvga.waitBeam();
  int bb = fb_width-(xx*sizeof(cmap2)*2); // put the unused space in the center
  for (col = 0; col < sizeof(cmap2); col++) {
    uvga.fillRect(col * xx, 2 * yy, (col * xx) + xx - 1, fb_height - 1, cmap2[(col + adv) % sizeof(cmap2)]);
    uvga.fillRect(bb+sizeof(cmap2)*xx + (col * xx), 2 * yy, bb+sizeof(cmap2)*xx + ((col * xx) + xx - 1), fb_height - 1, 0xff - cmap2[(col + adv) % sizeof(cmap2)]);
  }
  delay( dtime );

}


void doLines( int fb_width, int fb_height, int dtime ) {
  int col;
  if ( 0 > dtime ) return;
  // uvga.waitSync();
  //uvga.clear(0b11111111);
  for (col = 0; col < fb_width; col += 18) {
    uvga.drawLine(col, 0, col, fb_height, 0b00011100);
    uvga.drawLine(col + 9, 0, col + 9, fb_height, 0b00000011);
    Serial.print(".");
  }
  delay( dtime );
}

void testPrint() {
  int fb_width, fb_height;
  uvga.get_frame_buffer_size(&fb_width, &fb_height);
  Serial.print("\n millis::");
  Serial.print(millis());
  Serial.print("  F_CPU:");
  Serial.print(F_CPU);
  Serial.print("   F_BUS:");
  Serial.print(F_BUS);
  Serial.print("   fb_height:");
  Serial.print(fb_height);
  Serial.print("   fb_width:");
  Serial.println(fb_width);

}

void doRegister( int fb_width, int fb_height, int dtime ) {
  if ( 0 > dtime ) return;
  fb_width--;
  fb_height--;
  uvga.drawTri(fb_width, fb_height/2, 0, fb_height/2, fb_width/2, 0, 0b01101111);
  uvga.drawTri(fb_width, fb_height/2+1, 0, fb_height/2+1, fb_width/2, fb_height, 0b10010001);
  delay( dtime );
}
 
Last edited:
Defragster, I tried your testsktech - very nice !!

QIX: Serial5 - what causes the problems ? RX or TX ? Could you post your testsketch (or mail it to me) - I want to investigate the exact problem.
The new lib-version with static memory works great!
 
Last edited:
Defragster, I tried your testsktech - very nice !!

Do you see the odd darker bar between rectangles?

Glad it works - simple - hopefully valid code. I made the functions to isolate some stuff and then gave them the uniform 'delay' param. Glad I did the registration pointers to the edge - to confirm the display was adjusted right. That works well in setup - but gets annoying after that.

I'm not sure about the proper use of waitSync and waitBeam. With none it scrambles during update and with too many it flickers horribly. It moves nicely with no delays - but the upper right corner loses a triangle to the left. I suppose to should have an elapsedMillis to limit screen updates to 60 Hz instead of running each loop.
 
Hi,

yes, i have to activate "auto adjust", too. The right border was out of the screen without that.
And, I see this darker bars, too. Is it posssible, that it comes from the display ? What does the "contrast" setting exactly do ?

Edit: Do you have a TV with VGA Input ? Mine is not willing to display anything..
 
Last edited:
... What does the "contrast" setting exactly do ?

Edit: Do you have a TV with VGA Input ? Mine is not willing to display anything..

I plugged mine into the VGA port on my 'big screen' TV and it came up fine. I should modify the Register lines to print H/V resolution and FPU and BUS speed - perhaps just the first few times it comes up after booting so when it works it can be noted.

You mean on the display? Contrast is the difference between full black and white and the shades of gray you can see between as unique - given the light value of each (black isn't always no light) and full white gives a ratio # to compare. But on a given image adjusting to show the degree of white and dark to make it clear.
 
Modified version of the above is in the works - no delay - just a 16ms watch for elapsedMillis to have passed before bothering to do screen updates again. Will look and adjust based on time between waitSync() if I understand that now. This ideally leaves big% of the CPU time open for other tasks based on how long the full screen of rectangle writes takes - allowing for a new screen of data to be fully drawn 60 times - without delay.

I put the data noted above printed in the Register() code - at F_BUS=120 the text is indeed ~1 half char left shifted left. Going back to F_BUS=60 prints the text properly left justified - but needed to 'Auto Adjust' again to get the right side registration mark on the screen. So the bus speed affects the screen sync adjustment - and oddly the text placement gets shifted (first line is 'on' left edge after newline, subsequent lines have a TAB to make sure they show) - code soon:

20170929_000920.jpg
 
QIX: Serial5 - what causes the problems ? RX or TX ? Could you post your testsketch (or mail it to me) - I want to investigate the exact problem.

I just tested TX because I have nothing really connected.

The code is very simple. I use add
Code:
Serial5.begin(115200);
in setup and
Code:
Serial5.println("x");
in loop. My loop is empty because the whole screen is built in setup().

I can send you the full code this evening because I don't have it at work.
 
I put the data noted above printed in the Register() code - at F_BUS=120 the text is indeed ~1 half char left shifted left. Going back to F_BUS=60 prints the text properly left justified - but needed to 'Auto Adjust' again to get the right side registration mark on the screen. So the bus speed affects the screen sync adjustment - and oddly the text placement gets shifted (first line is 'on' left edge after newline, subsequent lines have a TAB to make sure they show) - code soon:
View attachment 11655

FTM channels should not be affected by F_BUS change. However, the exact value and the truncated value obtained in FTM MOD computation may be too far which generate this side effect.

This means I should define additional modelines taking into account F_BUS, not only F_CPU.
 
Back
Top