Trying to bring something like uVGA library to the Teensy4.
Now all MCUME emulators support VGA output!!!
https://www.youtube.com/watch?v=UE9MPr-iVOg
https://github.com/Jean-MarcHarvengt/VGA_t4
Printable View
Trying to bring something like uVGA library to the Teensy4.
Now all MCUME emulators support VGA output!!!
https://www.youtube.com/watch?v=UE9MPr-iVOg
https://github.com/Jean-MarcHarvengt/VGA_t4
Nice work!
Fantastic!
Go on for the 12 bit. It is so good to have an Amiga again. Thank you!
So nice :)
I just have to wait for some components and i try it , Amiga Forever ;)
Is the teensy 4.1 uae version updated for VGA on your github ? , i have look but i think it's the ili9341 version.
Cheers.
Emulator's code adapted for VGA is not yet published. Still trying to fix higher resolution for the Amiga and Atari ST!
I just made a R2R VGA DAC that output perfect colors , but when i try to upload the schematic (png 1280 x 688) it don't work.
So the schematic is dropped to google drive : https://drive.google.com/file/d/12U0...ew?usp=sharing
Cheers.
This VGA to HDMI converter work fine with your project :
https://www.amazon.fr/gp/product/B01...?ie=UTF8&psc=1
It's french amazon , but it must be available on other country too ...
Cheers.
I will upload the schematic to the GIT website. Thanks a lot!
After playing around i added some functionalities to the graphics lib :
void drawline(int16_t x1, int16_t y1, int16_t x2, int16_t y2, vga_pixel color);
void drawcircle(int16_t x, int16_t y, uint16_t radius, vga_pixel color);
void drawfilledcircle(int16_t x, int16_t y, int16_t radius, vga_pixel fillcolor, vga_pixel bordercolor);
void drawellipse(int16_t cx, int16_t cy, uint16_t radius1, uint16_t radius2, vga_pixel color);
void drawfilledellipse(int16_t cx, int16_t cy, uint16_t radius1, uint16_t radius2, vga_pixel fillcolor, vga_pixel bordercolor);
void drawtriangle(int16_t ax, int16_t ay, int16_t bx, int16_t by, int16_t cx, int16_t cy, vga_pixel color);
void drawfilledtriangle(int16_t ax, int16_t ay, int16_t bx, int16_t by, int16_t cx, int16_t cy, vga_pixel fillcolor, vga_pixel bordercolor);
you can see the result here :
https://drive.google.com/file/d/1qb_...ew?usp=sharing
I just see one problem , the circle are ... ovale ;)
The horizontal and vertical lines are spaced from 10 pixels , here we see that the pixels have a size in x of 2 and 1 in Y.
Well ... i will go for manage my circle differently :)
Cheers.
PS : for the schematic , take this one , it's the original before reduction :
https://drive.google.com/file/d/15tz...ew?usp=sharing
Thanks. I will merge your code into the git tomorrow.
In meanwhile, I pushed the VGA support code to the teensyuae41.
https://github.com/Jean-MarcHarvengt/MCUME
I was trying the all day to introduce a 640x240 mode but I don't manage.
Still runs at 352x240 (320x240 in fact) wo sound but not too bad...even in RRRGGGBB mode.
Pay attention to iopins.h for the 3 keys needed an the joypad,... and you the need psram soldered of course!
The code is here :
https://drive.google.com/file/d/1il8...ew?usp=sharing
I don't have finished the "Quad" function , it need pre calculed sin/cos for efficiency , as i am new in teensy world , i have do allot with STM32F4 / F7 in the past , and need some time to understand how everything is working :)
And thanks for your code update , i will test it tomorrow ;)
Here is the source from my old STM32 library for the exact timing of some VGA resolution :
HSync_Level and VSync_Level change , it depend the resolution , you have to take care on this too ...
PLLSAI_VCO , PLLSAI_R , PLLSAIDivR are just for STM32Fxx timing .... most important is to stay in the 25.175Mhz range , a little drift is working so long it's not too much :D
I hope it can help you for the 640 x 240 resolution ...
Code:// VGA Parameter common to all resolution made with
// the standard 640x480 at 60Hz base.
// 25.175Mhz base (here is 25.187 Mhz)
#if defined USE_240x320_60 || defined USE_320x240_60 || defined USE_320x240_60_DOUBLE || defined USE_640x480_60
#define GFX_H_Front_Porch ((uint16_t)8) //pixels
#define GFX_H_Sync ((uint16_t)96) //pixels
#define GFX_H_Back_Porch ((uint16_t)40) //pixels
#define GFX_V_Front_Porch ((uint16_t)2) //lines
#define GFX_V_Sync ((uint16_t)2) //lines
#define GFX_V_Back_Porch ((uint16_t)25) //lines
#define GFX_Total_line_length ((uint16_t)800) //pixels
#define GFX_Total_Height ((uint16_t)525) //lines
#define Freq_PLLSAI_VCO ((uint16_t)403) //Mhz
#define Freq_PLLSAI_R ((uint16_t)2) //Div 2 (403/2 = 201.5 Mhz)
#define Freq_PLLSAIDivR ((uint16_t)7) //Div 8 (201.5/8 = 25.187 Mhz) do -1 from divider
#define HSync_Level ((uint16_t)0) //Low
#define VSync_Level ((uint16_t)0) //Low
#endif
#ifdef USE_240x320_60
#define GFX_H_Left_Border ((uint16_t)208) //pixels
#define GFX_H_Video_Line ((uint16_t)240) //pixels
#define GFX_H_Right_Border ((uint16_t)208) //pixels
#define GFX_V_Top_Border ((uint16_t)88) //lines
#define GFX_V_Video_Height ((uint16_t)320) //lines
#define GFX_V_Bottom_Border ((uint16_t)88) //lines
#endif
#ifdef USE_320x240_60
#define GFX_H_Left_Border ((uint16_t)168) //pixels
#define GFX_H_Video_Line ((uint16_t)320) //pixels
#define GFX_H_Right_Border ((uint16_t)168) //pixels
#define GFX_V_Top_Border ((uint16_t)128) //lines
#define GFX_V_Video_Height ((uint16_t)240) //lines
#define GFX_V_Bottom_Border ((uint16_t)128) //lines
#endif
#ifdef USE_320x240_60_DOUBLE
#define GFX_H_Left_Border ((uint16_t)8) //pixels
#define GFX_H_Video_Line ((uint16_t)640) //pixels
#define GFX_H_Right_Border ((uint16_t)8) //pixels
#define GFX_V_Top_Border ((uint16_t)8) //lines
#define GFX_V_Video_Height ((uint16_t)480) //lines
#define GFX_V_Bottom_Border ((uint16_t)8) //lines
#endif
#ifdef USE_640x480_60
#define GFX_H_Left_Border ((uint16_t)8) //pixels
#define GFX_H_Video_Line ((uint16_t)640) //pixels
#define GFX_H_Right_Border ((uint16_t)8) //pixels
#define GFX_V_Top_Border ((uint16_t)8) //lines
#define GFX_V_Video_Height ((uint16_t)480) //lines
#define GFX_V_Bottom_Border ((uint16_t)8) //lines
#endif
#ifdef USE_640x350_70 //25.175 Mhz
#define GFX_H_Left_Border ((uint16_t)0) //pixels
#define GFX_H_Video_Line ((uint16_t)640) //pixels
#define GFX_H_Right_Border ((uint16_t)0) //pixels
#define GFX_V_Top_Border ((uint16_t)0) //lines
#define GFX_V_Video_Height ((uint16_t)350) //lines
#define GFX_V_Bottom_Border ((uint16_t)0) //lines
#define GFX_H_Front_Porch ((uint16_t)16) //pixels
#define GFX_H_Sync ((uint16_t)96) //pixels
#define GFX_H_Back_Porch ((uint16_t)48) //pixels
#define GFX_V_Front_Porch ((uint16_t)37) //lines
#define GFX_V_Sync ((uint16_t)2) //lines
#define GFX_V_Back_Porch ((uint16_t)60) //lines
#define GFX_Total_line_length ((uint16_t)800) //pixels
#define GFX_Total_Height ((uint16_t)449) //lines
#define Freq_PLLSAI_VCO ((uint16_t)403) //Mhz
#define Freq_PLLSAI_R ((uint16_t)2) //Div 2 (403/2 = 201.5 Mhz)
#define Freq_PLLSAIDivR ((uint16_t)7) //Div 8 (201.5/8 = 25.187 Mhz) do -1 from divider
#define HSync_Level ((uint16_t)1) //High
#define VSync_Level ((uint16_t)0) //Low
#endif
#ifdef USE_640x400_70 //25.175 Mhz
#define GFX_H_Left_Border ((uint16_t)0) //pixels
#define GFX_H_Video_Line ((uint16_t)640) //pixels
#define GFX_H_Right_Border ((uint16_t)0) //pixels
#define GFX_V_Top_Border ((uint16_t)0) //lines
#define GFX_V_Video_Height ((uint16_t)400) //lines
#define GFX_V_Bottom_Border ((uint16_t)0) //lines
#define GFX_H_Front_Porch ((uint16_t)16) //pixels
#define GFX_H_Sync ((uint16_t)96) //pixels
#define GFX_H_Back_Porch ((uint16_t)48) //pixels
#define GFX_V_Front_Porch ((uint16_t)12) //lines
#define GFX_V_Sync ((uint16_t)2) //lines
#define GFX_V_Back_Porch ((uint16_t)35) //lines
#define GFX_Total_line_length ((uint16_t)800) //pixels
#define GFX_Total_Height ((uint16_t)449) //lines
#define Freq_PLLSAI_VCO ((uint16_t)403) //Mhz
#define Freq_PLLSAI_R ((uint16_t)2) //Div 2 (403/2 = 201.5 Mhz)
#define Freq_PLLSAIDivR ((uint16_t)7) //Div 8 (201.5/8 = 25.187 Mhz) do -1 from divider
#define HSync_Level ((uint16_t)0) //Low
#define VSync_Level ((uint16_t)1) //High
#endif
[sorry to snoop on the "Quad" code, but I couldn't help noticing]
I'm sure you only need to call sine and cosine once each for the rectangle drawing, using transformation
matrix... Transform one coord of one corner (w/2, h/2), transform two vectors for the sides (w, 0), (0, h),
reconstruction of the other corners is then addition/subtraction of vectors.
Calculating four different angles doesn't seem an efficient method to me.
I just tested uae on T4.1 ;)
So great to see a full speed Amiga coming out of this little Teensy !!
I need now a keyboard , i take a look at your i2c keyboard , your schematic is 'Ugly' :)
Do you have something more explicit to build the KB ? , you use Atmega328 (same as arduino nano) , now your pinout and key distribution made some knot into my poor brain.
It will be better with a real schematic or is it possible to connect a usb kb directly ?
Some game need more than one disk , and i was not able to 'change' disk when requested , is it a way to do it ?
Cheers.
The original idea was to create a portable amiga with the ILI display, so I had chosen to build a I2C interfaced keyboard matrix ;-)
I did not try to add usb keyboard support but should be doable.
I need to find a usb cable. I can have a look this week.
I received my PCM5102a sound module today.
I just connected it over I2S and it sounds great together with the VGA out.
It disturbs the line interrupt a bit but sound is ok!
May I ask you to try something for me...
You probably have a better cable than me and you also use the R2R ladder you proposed.
Could try to activate sound in platform_config.h on the amiga emulator.
Just uncomment HAS_SOUND line...
Do you also have disturbance on the video lines?
Impressive the 1062 allows upgrade from the 6502!
For USB Host keyboard ref perhaps:: On github.com/FrankBoesing/Teensy64 3 years back - Commodore C64 Emulation on a Teensy 3.6 Microcontroller used USB for keyboard - also did VGA and ILI9341. It also had PS/2 keyboard support.
Hi :)
I tested , i get disturbance in video line , when sound is activated.
I2C Keyboard is a good idea , but then we need a ... real ... schematic ;)
On this picture you can see the disturbance on the vertical lines (you have to zoom in):
https://drive.google.com/file/d/1cO7...ew?usp=sharing
Cheers.
Hi :D
Today i connected a PS2 or (USB to PS2) keyboard to a arduino nano who read the KB and send the character out to I2C when requested.
Is it something to know to made it work like your I2C KB ? so it will be good for all of your emulators.
Cheers.
It is a great idea indeed. The I2C protocol is quite simple. I just reads (one single read command) an array of bytes where each bit reflects the status of one key. I had 2 variants. 4 rows of 10 keys (4bits-4bits-4bits ...4bits grouped in bytes per 2 columns) => 5 bytes. I also had variant with 5 rows of 10 keys but the portable console T4 has only 4x10 keys.
About Teensy64, it is indeed the project of Frank! I forked the code when I added support for a on screen keyboard using the ILI touch screen when using the VGA output (uVGA) on the T3.6.
I tried activating USB and I think it will also work to add USB keyboard directly on UAE. I found a USB connector I will try to connect it to the T4 tomorrow.
I am off next week so I will measure the accuracy of the H-pulses with a scope. Still did not manage to get proper clock for 640x240.
I think it was a miracle to have 352x240 working!
Thanks for your interest to the project ;-)
Hi :)
Strange that you can't get the 640 x 240 resolution , it must be something with the timing.
I got problems with that some years ago with the STM32F407 MCU , when everything was ok the 640 x 480 native VGA was perfect.
Now with STM32H7 i'm sure we can have the 800x600 or 1024x768 , but it use the DMA2D + LTDC ...
Teensy 4.1 got 200+ Mhz than the STM32H7 then it will work too ... for sure ... ;)
Now for the keyboard , i found this in 'emuapi.h' :
I presume that is the keycode , you are using 40 keys , on your picture they are no characters written on the keys :eek:Code:#ifdef HAS_I2CKBD
const unsigned short i2ckeys[] = {
0X0080,0X0008,0X0180,0X0108,0X0280,0X0208,0X0380,0X0308,0X0480,0X0408,
0X0040,0X0004,0X0140,0X0104,0X0240,0X0204,0X0340,0X0304,0X0440,0X0404,
0X0020,0X0002,0X0120,0X0102,0X0220,0X0202,0X0320,0X0302,0X0420,0X0402,
0X0010,0X0001,0X0110,0X0101,0X0210,0X0201,0X0310,0X0301,0X0410,0X0401 };
//0X0580,0X0540,0X0520,0X0510,0X0508,0X0504,0X0502,0X0501,0X0680,0X0640 };
#endif
Is there a corresponding table to know what key trigger what character ?
I will take it as example for finish my actual setup with the i2c (real keyboard).
Only KB with cable are working actually , i tested 2 wireless KB with no luck.
I hope it will not take precious resources :)Quote:
I tried activating USB and I think it will also work to add USB keyboard directly on UAE
Lol , thanks to you who made it work !Quote:
Thanks for your interest to the project ;-)
Cheers.
indeed, each emulator in MCUME (computer with a keyboard) has a similar table.
The table you pasted above is somehow derived from the I2C data read (see emuapi.cpp for details). Kind of row+col code.
Next to that you have a keymap table of same size with the code injected to the emulator itself.
In case of the amiga, there are 2 keymaps table. One where Function keys are sent in first row, one where digits are sent.
You toggle via a user button between the 2 keymaps
Not all keys are mapped in current layout but it can be extended.
const unsigned short key_map1[]={
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
const unsigned short key_map2[]={
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
In case of the amiga each entry in the keymap is an index to the amiga key but does not matter.
Ok :)
So i will look that my I2C code correspond to yours.
Is just that i put only one char on I2C bus each time , i see in 'emuapi.c' that you get 7 bytes each time ....
So i have to made some mods :D
Or add a new #define for 102 key KB ... will see ....
Thanks for your infos :)
Cheers.