Teensy 3.6 VGA driver

I plan to add new parameters to modeline settings to create something like letterbox image. Only 2 new parameters should be required, the number of lines to display as empty lines at top and bottom of screen.

I just committed code allowing creation of modelines with black border on top and bottom of the screen.

I also add a new 240MHz demo (puls) using such a modeline. The demo is a bit slow (~ 2 fps) because it uses a lot of floating computations and I think little teensy is a bit too underpower to perform realtime ray casting :)

This demo also uses a double buffering with a DMA channel copying the offscreen buffer to the frame buffer.

IMG_20171007_174046.jpg IMG_20171007_174404.jpg IMG_20171007_175241.jpg

It is possible to activate fish eye mode by uncommenting #define FISH_EYE_LENS line.
 
Last edited:
2fps is not that bad if every pixel is ray-casted with floats.

Yes, all of them with a bunch of sqrt, sin, cos, * and / . FPU is not bad at all but integer<=>float conversions seems to be rather slow. Performing all computations is faster than having a part of them in integer
 
Yes, all of them with a bunch of sqrt, sin, cos, * and / . FPU is not bad at all but integer<=>float conversions seems to be rather slow. Performing all computations is faster than having a part of them in integer

Assuming that you don't need the precision, always use the float keyword instead of double on the Teensy system. Teensy 3.5/3.6 has hardware support for single precision floating point, but it has to emulate double precision.

On the 3.6, be sure to use the float versions of sin, cos, sqrt, etc. that have a 'f' suffix (i.e. sinf, cosf, sqrtf, etc.). The normal sin is done in double precision. The sinf function is done in single precision, which is done in hardware. If you use something that returns double in an expression, it forces the entire expression to be done in double precision.

While Paul adds a switch to make all floating point constants single precision on Teensy builds, it is probably a good habit to get into to add a 'f' suffix to all explicit constants.
 
Assuming that you don't need the precision, always use the float keyword instead of double on the Teensy system. Teensy 3.5/3.6 has hardware support for single precision floating point, but it has to emulate double precision.

Unfortunately, that's already what I did. The only solution I can see is fixed point arithmetic but this means uint64_t usage at least during multiplications and divisions which may be even slower. Using large precalculated arrays is not a solution because with double buffering, less than 30KB remains.

I also don't want to spend too much time on a demo because it is just a demo and it is not bad for a CPU without graphic card :D
 
Hi qix,

please write me a mail with your address...
I want to send you a VGA(with a few extras) Board.

teensy64vga.jpg
 
Last edited:
I think I have found why usb usage is disturbing image generation. The problem is not in fact USB itself but the location of its descriptors and buffers.

2 sections are defined in usb_dev.c and usb_mem.c, .usbdescriptortable and .usbbuffers. These 2 sections are located at address 1fff0000 and 1fff03d0 which are at the beginning of SRAM_L. USBFS has its own DMA controller and access to crossbar directly as a master, in the same manner as the DMA controller (eDMA). That's why despite all the configuration I made on eDMA, the problem remains. USBHS also has its own DMA controller.

I think if I can move these sections at the end of SRAM_U, everything should work fine.
 
Failed to move? or did the move and it failed to help?

I successfully moved the sections by modifying mk66fx1m0.ld and verified using objdump but unfortunately, it changes nothing.

I should receive my new logic analyzer soon. It will be able to work at 100MHz. With it, I may find what occurs. Perhaps the problem does not come from DMA at all but from FTM, even if it should not.
 
I have my Sony "Bravia" TV working. As I suspected some posts earlier: On PIN 9 of the VGA socket 5 volts are necessary. It detects 800 x 600 60Hz Mode.
 
I have my Sony "Bravia" TV working. As I suspected some posts earlier: On PIN 9 of the VGA socket 5 volts are necessary. It detects 800 x 600 60Hz Mode.

It is not mandatory. About pin 9, I found this:
Pin 9 is now utilised for a 5v DC power rail, and pin 15 is the VESA DDC (Display Data Channel). The power line is designed to run the EDID or DDC chip inside a display so that it can be identified when it's not externally powered, while the DDC line carries that information back to the source device.

Whether or not your TV requires this power for the DDC handshake varies between manufacturers and their chosen implementations on each model of display. Some screens will happily work without pin 9 so long as they get power from the wall, while others will refuse to 'handshake' unless it's present.

Where did you pick 5V from ? Vin or VUSB ? booster from 3.3v ?
 
Currently, Vin (like on the boards i sent you - there is a jumper on the backside to connect Pin 9 with Vin - have you got my mail ? ). I'll change that to VUSB for the next revision, and remove the jumper.
 
Currently, Vin (like on the boards i sent you - there is a jumper on the backside to connect Pin 9 with Vin - have you got my mail ? ). I'll change that to VUSB for the next revision, and remove the jumper.

Not yet, no mail today at all but it still can come until ~2pm.
 
Not yet, no mail today at all but it still can come until ~2pm.

I think I need more holidays (or sleep, perhaps 5hr/day is not enough :eek:), yesterday was sunday and no mail is delivered on sunday.

@Frank B: I have not received your parcel today but I have received my logic analyzer.

I tried my analyzer on my flexbus code and I think I missed something. I displayed a black image thus the only changes are address values. Here is the signals I have.

screen-2017-10-16-19-04-31.jpg

FB_CS is flexbus chip select, FB_ALE is address latch enable and FB_AD0 is bit 0.

When FB_ALE goes up, FB_AD0 carries address to use and we can see FB_AD0 beeing low the first time and high the second time. It is normal because I write on address X, X+1, X+2, X+3 and restart from X. Bit 0 is 0 (even address) the first time and 1 (odd address) the second time.

When FB_ALE goes down, FB_CS goes down to select the component to use and at the same time, FB_AD0 carries data.

My problem is that after FB_ALE, FB_CS goes down, up and down again which should not occur according to flexbus timing diagram. Moreover, this occurs only on even address. It is not noise on the pin, it repeats perfectly.

The correct timing should be something like this.

screen-2017-10-16-19-21-25.png

very weird...:confused:
 
very weird...:confused:

It was my fault. lowering flexbus frequency or increasing analyzer speed fixed the problem.

Now, I am waiting for my latest component (8 bit positive trigger flip-flop in soic20). The previous one (16 bit in tsop 44) was too hard to wire on a breadboard, all the wires produced a lot of noises.

screenshot-cd03e170.jpg

The latch should trigger when CS goes up (green line in the pix). This will keep data and removes address pulses, pixels were black here thus D0 is always low.

@Frank: I just received your board. I will try to solder one at the end of the month. Currently, I try to finish all the work in my garage before it gets too cold. Thanks again.
 
Last edited:
Here is few news about flexbus version.

Yesterday, I finally received my LVTH574DW and I solder everything this morning. Unlike my first prototype on breadboard, I have no more noise now. The image is rock solid, even when USB is connected. The awful image produced when using Serial5 (see post 110) is no more. Flexbus version is a lot faster. When flexbus runs at full speed, even with a 3 cycle wait state, rendered 703x300 image is narrower than the GPIO version thanks to 32 bits access.

However, I still have one problem to solve. I don't know where the vertical grey lines come from. Even when displaying a black image, I have thin brown vertical lines. They are not very stable and act like noise but despite their movements, the pixels do not move.

IMG_20171021_095722.jpg
This image is taken with heavy Serial5 writes.

LVTH574 should be fast enough (<5ns max). Time to go back to logical analyzer to see flip-flop output.
 
That sounds promising and good! Except you only show a bad picture :( I take it those puzzling 'vertical grey lines' are only during Serial5 access? What is the total added parts count and cost to get the external RAM and control working? Faster? More fps on the RayTrace demo or is that CPU bound?
 
That sounds promising and good! Except you only show a bad picture :( I take it those puzzling 'vertical grey lines' are only during Serial5 access? What is the total added parts count and cost to get the external RAM and control working?

Unfortunately, no. Grey lines are always present, whatever the CPU does. Weird thing, the logical analyzer shows nothing on flip-flop outputs (voltage may be too low due to resistors). Even weirder, the lines are nearly non-existant on my TV :confused:. I think I will order a PCB to have clean path between all lines.

This version still has no extra RAM. Only one component is added, 74LVTH574DW, ~3.5$ for 5 on ebay + 4$ shipping cost. I took a SOIC20 component because it is easier to solder.

Faster? More fps on the RayTrace demo or is that CPU bound?

No, this demo is CPU limited. I reorganize some parts of the code and it now reaches 3fps but I am out of idea to make it faster.

Earlier, I said flexbus pushs data faster. Here is an image of 703x300 when flexbus runs at full speed without wait state. Roughly, it should be able to push more than ~2100pixels per line in 800x600, not bad. Normal pixel clock in this resolution is 40Mhz, with some many pixels, it makes ~120Mhz (a bit strange because flexbus max frequency is 60Mhz according to reference manual, maybe a side effect of 240Mhz overclocking). Another big advantage of flexbus is its clocking capabilities. It is possible to divide its frequency by any value between 1 to 16 and add 0-63 wait-states. This will allow creation of more resolution.

IMG_20171021_102111.jpg
 
mysterious grey lines

I change my image settings to produce a wonderful 15x300 picture (yes, fifteen). Flexbus runs at 1/3 of bus speed, CS signal is delayed by 3 cycles and 63 wait-state cycles are added. This lets plenty of time before and after latch trigger and the latch only triggers 16 times per line.

IMG_20171024_181030.jpg

On the picture (sorry for the bad quality), we can see light grey lines are slightly after latch triggers (see red arrows). The main thing I don't understand is why the problem happens even when pixel color does not change (white area). Can it be possible that the latch cannot provide enough power on output pins after triggering ?

If someone has an idea, I gladly accept it.
 
Hi qix,
I have a solution for my usb-host problem, I think.
I add two more channels to the FTM with modified timing. They have interrupts enabled and let me en/disable the usb-host thing and read gpios (gpio-access causes flicker, too (same periphal bus))
Code:
/*
    The USB HOST feature causes pixel-flicker on VGA, because it with GPIO on the same periphal bus.
    These functions sync to the HSYNC-Signal, and enable USB on the right edge of the screen only.
    In addition, all GPIOs are read.
*/
#if VGA && USBHOST
volatile int16_t rasterLineCounterVGA;
FASTRUN void ftm0_isr(void) {

    uint16_t c = rasterLineCounterVGA;
    uint32_t i1 = FTM0_C2SC;
    if (i1 & FTM_CSC_CHF) {
        FTM0_C2SC = i1 & ~FTM_CSC_CHF;
        USBHS_USBCMD |= ( USBHS_USBCMD_PSE /* | USBHS_USBCMD_ASE */); //Enable USB Host Periodic Transfers
        READGPIO;
        c++;
        if (c == modeline.vtotal) {c = 0;}
        rasterLineCounterVGA = c;
//        digitalWriteFast(13,0);
    } else {
        uint32_t i2 = FTM0_C3SC;
        FTM0_C3SC = i2 & ~FTM_CSC_CHF;
        if (c > 51 && c < 593) USBHS_USBCMD &= ~(USBHS_USBCMD_PSE /* | USBHS_USBCMD_ASE */);//Disable USB Host Periodic Transfers
//      digitalWriteFast(13,1);
    }
}

void add_uVGAhsync(void) {
  Serial.println("USB-HOST: Disabling Async transfers.");
  USBHS_USBCMD &= ~(USBHS_USBCMD_ASE);//Disable USB Host Async Transfers
  
  Serial.println("uVGA: Add hsync interrupt.");  
  // Add channels 2 + 3 to FTM 0 as triggers for FTM0 interrupt
  //stop FTM0
  uint32_t sc = FTM0_SC;
  FTM0_SC = 0;
#if 1
  Serial.print("FTM 0 Channel 0 SC: 0x");
  Serial.println(FTM0_C0SC, HEX);
  Serial.print("FTM 0 Channel 0 V:");
  Serial.println(FTM0_C0V);
  Serial.print("FTM 0 Channel 1 SC: 0x");
  Serial.println(FTM0_C1SC, HEX);
  Serial.print("FTM 0 Channel 1 V:");
  Serial.println(FTM0_C1V);
#endif
  //Add channels 2+3
  FTM0_C2SC = FTM0_C0SC | FTM_CSC_CHIE;
  FTM0_C2V = FTM0_C0V - 260; //Value determined experimentally
  FTM0_C3SC = FTM0_C1SC | FTM_CSC_CHIE;
  FTM0_C3V = FTM0_C1V + 150; //Value determined experimentally
  const uint32_t channel_shift = (2 >> 1) << 3;    // combine bits is at position (channel pair number (=channel number /2) * 8)
  FTM0_COMBINE |= ((FTM0_COMBINE & ~(0x000000FF << channel_shift)) | ((FTM_COMBINE_COMBINE0 | FTM_COMBINE_COMP0) << channel_shift));

  // re-start FTM0
  FTM0_SC = sc;
  
  noInterrupts();
  NVIC_SET_PRIORITY(IRQ_FTM0, 0);
  NVIC_ENABLE_IRQ(IRQ_FTM0);
  uvga.waitSync();
  rasterLineCounterVGA = 0;
  interrupts();
}
#endif
What do you think ? Does this make sense, and do you know a better way?
Edi: I greatly under-estimated the needed communication to the keyboard. Keypresses have a little lag now, but that's the maximum time to enable USB - a bit more causes flicker, again...
 
Last edited:
Back
Top