Skip to content

Commit

Permalink
Merge pull request #93 from abcbarryn/master
Browse files Browse the repository at this point in the history
Update TVout to support the Arduino Leonardo
  • Loading branch information
Avamander committed Oct 12, 2015
2 parents 7deafd6 + 86c7642 commit a3d3f57
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 68 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@

This is a library for generating composite video on an ATmega microcontroller.

The library can create NTSC or PAL at a resolution of 128x96. The library currently works on ATmega168, ATmega328, ATmega1280, ATmega2560, ATmega644P, ATmega1284P, ATmega90USB1286 and more can be added by editing one file.
This branch of the TVout library has been patched to allow use with the Arduino Leonardo. The goal of this project is to create a simple interupt driven library for generating composite video on a single AVR chip.

Currently the output is NTSC or PAL at a resolution of 128x96 by default. The library currently works on ATmega168,328,1280,2560,644p,1284p,32U4,AT90USB1286 and more can be added by editing spec/hardware_setup.h.

There are some timing issues with the m1284p, may be related to sanguino core.

```
MCU SYNC VIDEO AUDIO Arduino SYNC VIDEO AUDIO
m168,m328 B 1 D 7 B 3 NG,Decimila,UNO 9 7 11
m1280,m2560 B 5 A 7 B 4 Mega 11 A7(D29) 10
m644,m1284p D 5 A 7 D 7 sanguino 13 A7(D24) 8
m32u4 B 5 B 4 B 7 Leonardo 9 8 11
AT90USB1286 B 5 F 7 B 4 -- -- -- --
```

##Connections

SYNC is on OCR1A and AUDIO is on OC2A
SYNC is on OCR1A and AUDIO is on OCR2A (except on the Arduino Leonardo, where AUDIO is on OCR0A)

There are some timing issues with the m1284p, may be related to sanguino core.

On NG, Decimila, UNO and Nano the sync is pin 9, video on 7 and audio on 11. On Mega2560 sync is pin 11, video is on A7(D29) and audio is on pin 10.




##Examples

https://youtu.be/MEg_V4YZDh0
Expand Down
7 changes: 6 additions & 1 deletion TVout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ unsigned char TVout::get_pixel(uint8_t x, uint8_t y) {
* The color of the line.
* (see color note at the top of this file)
*/
/* Patched to allow support for the Arduino Leonardo */
void TVout::draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, char c) {

if (x0 > display.hres*8 || y0 > display.vres || x1 > display.hres*8 || y1 > display.vres)
Expand Down Expand Up @@ -809,7 +810,11 @@ void TVout::tone(unsigned int frequency, unsigned long duration_ms) {
if (frequency == 0)
return;

#if defined(__AVR_ATmega32U4__)
#define TIMER 0
#else
#define TIMER 2
#endif
//this is init code
TCCR2A = 0;
TCCR2B = 0;
Expand Down Expand Up @@ -874,4 +879,4 @@ void TVout::tone(unsigned int frequency, unsigned long duration_ms) {
void TVout::noTone() {
TCCR2B = 0;
PORT_SND &= ~(_BV(SND_PIN)); //set pin 11 to 0
} // end of noTone
} // end of noTone
206 changes: 145 additions & 61 deletions TVout/TVout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ char TVout::begin(uint8_t mode, uint8_t x, uint8_t y) {
} // end of begin


/* Stop video render and free the used memory.
*/
void TVout::end() {
TIMSK1 = 0;
free(screen);
}


/* Fill the screen with some color.
*
* Arguments:
Expand Down Expand Up @@ -122,7 +130,8 @@ void TVout::fill(uint8_t color) {

/* Gets the Horizontal resolution of the screen
*
* Returns the horizonal resolution.
* Returns:
* The horizonal resolution.
*/
unsigned char TVout::hres() {
return display.hres*8;
Expand Down Expand Up @@ -289,69 +298,76 @@ unsigned char TVout::get_pixel(uint8_t x, uint8_t y) {
* The color of the line.
* (see color note at the top of this file)
*/
/* Patched to allow support for the Arduino Leonardo */
void TVout::draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, char c) {

if (x0 > display.hres*8 || y0 > display.vres || x1 > display.hres*8 || y1 > display.vres)
return;
int e;
signed int dx,dy,j, temp;
signed char s1,s2, xchange;
signed int x,y;
if (x0 == x1)
draw_column(x0,y0,y1,c);
else if (y0 == y1)
draw_row(y0,x0,x1,c);
else {
int e;
signed int dx,dy,j, temp;
signed char s1,s2, xchange;
signed int x,y;

x = x0;
y = y0;
x = x0;
y = y0;

//take absolute value
if (x1 < x0) {
dx = x0 - x1;
s1 = -1;
}
else if (x1 == x0) {
dx = 0;
s1 = 0;
}
else {
dx = x1 - x0;
s1 = 1;
}
//take absolute value
if (x1 < x0) {
dx = x0 - x1;
s1 = -1;
}
else if (x1 == x0) {
dx = 0;
s1 = 0;
}
else {
dx = x1 - x0;
s1 = 1;
}

if (y1 < y0) {
dy = y0 - y1;
s2 = -1;
}
else if (y1 == y0) {
dy = 0;
s2 = 0;
}
else {
dy = y1 - y0;
s2 = 1;
}
if (y1 < y0) {
dy = y0 - y1;
s2 = -1;
}
else if (y1 == y0) {
dy = 0;
s2 = 0;
}
else {
dy = y1 - y0;
s2 = 1;
}

xchange = 0;
xchange = 0;

if (dy>dx) {
temp = dx;
dx = dy;
dy = temp;
xchange = 1;
}
if (dy>dx) {
temp = dx;
dx = dy;
dy = temp;
xchange = 1;
}

e = ((int)dy<<1) - dx;
e = ((int)dy<<1) - dx;

for (j=0; j<=dx; j++) {
sp(x,y,c);
for (j=0; j<=dx; j++) {
sp(x,y,c);

if (e>=0) {
if (xchange==1) x = x + s1;
else y = y + s2;
e = e - ((int)dx<<1);
if (e>=0) {
if (xchange==1) x = x + s1;
else y = y + s2;
e = e - ((int)dx<<1);
}
if (xchange==1)
y = y + s2;
else
x = x + s1;
e = e + ((int)dy<<1);
}
if (xchange==1)
y = y + s2;
else
x = x + s1;
e = e + ((int)dy<<1);
}
} // end of draw_line

Expand All @@ -369,7 +385,7 @@ void TVout::draw_line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, char c) {
* the color of the fill.
* (see color note at the top of this file)
*/
void TVout::fill_line(uint8_t line, uint16_t x0, uint16_t x1, uint8_t c) {
void TVout::draw_row(uint8_t line, uint16_t x0, uint16_t x1, uint8_t c) {
uint8_t lbit, rbit;

if (x0 == x1)
Expand Down Expand Up @@ -407,7 +423,60 @@ void TVout::fill_line(uint8_t line, uint16_t x0, uint16_t x1, uint8_t c) {
screen[x0] ^= rbit;
}
}
} // end of fill_line
} // end of draw_row


/* Fill a column from one point to another
*
* Argument:
* row:
* The row that fill will be performed on.
* y0:
* edge 0 of the fill.
* y1:
* edge 1 of the fill.
* c:
* the color of the fill.
* (see color note at the top of this file)
*/
void TVout::draw_column(uint8_t row, uint16_t y0, uint16_t y1, uint8_t c) {

unsigned char bit;
int byte;

if (y0 == y1)
set_pixel(row,y0,c);
else {
if (y1 < y0) {
bit = y0;
y0 = y1;
y1 = bit;
}
bit = 0x80 >> (row&7);
byte = row/8 + y0*display.hres;
if (c == WHITE) {
while ( y0 <= y1) {
screen[byte] |= bit;
byte += display.hres;
y0++;
}
}
else if (c == BLACK) {
while ( y0 <= y1) {
screen[byte] &= ~bit;
byte += display.hres;
y0++;
}
}
else if (c == INVERT) {
while ( y0 <= y1) {
screen[byte] ^= bit;
byte += display.hres;
y0++;
}
}
}
}


/* draw a rectangle at x,y with a specified width and height
Expand All @@ -433,7 +502,7 @@ void TVout::draw_rect(uint8_t x0, uint8_t y0, uint8_t w, uint8_t h, char c, char

if (fc != -1) {
for (unsigned char i = y0; i < y0+h; i++)
fill_line(i,x0,x0+w,fc);
draw_row(i,x0,x0+w,fc);
}
draw_line(x0,y0,x0+w,y0,c);
draw_line(x0,y0,x0,y0+h,c);
Expand Down Expand Up @@ -466,10 +535,12 @@ void TVout::draw_circle(uint8_t x0, uint8_t y0, uint8_t radius, char c, char fc)
int ddF_y = -2 * radius;
int x = 0;
int y = radius;
uint8_t pyy = y,pyx = x;


//there is a fill color
if (fc != -1)
fill_line(y0,x0-radius,x0+radius,fc);
draw_row(y0,x0-radius,x0+radius,fc);

sp(x0, y0 + radius,c);
sp(x0, y0 - radius,c);
Expand All @@ -485,11 +556,20 @@ void TVout::draw_circle(uint8_t x0, uint8_t y0, uint8_t radius, char c, char fc)
x++;
ddF_x += 2;
f += ddF_x;
if (fc != -1) { //there is a fill color
fill_line(y0+y,x0-x,x0+x,fc);
fill_line(y0-y,x0-x,x0+x,fc);
fill_line(y0+x,x0-y,x0+y,fc);
fill_line(y0-x,x0-y,x0+y,fc);

//there is a fill color
if (fc != -1) {
//prevent double draws on the same rows
if (pyy != y) {
draw_row(y0+y,x0-x,x0+x,fc);
draw_row(y0-y,x0-x,x0+x,fc);
}
if (pyx != x && x != y) {
draw_row(y0+x,x0-y,x0+y,fc);
draw_row(y0-x,x0-y,x0+y,fc);
}
pyy = y;
pyx = x;
}
sp(x0 + x, y0 + y,c);
sp(x0 - x, y0 + y,c);
Expand Down Expand Up @@ -730,7 +810,11 @@ void TVout::tone(unsigned int frequency, unsigned long duration_ms) {
if (frequency == 0)
return;

#if defined(__AVR_ATmega32U4__)
#define TIMER 0
#else
#define TIMER 2
#endif
//this is init code
TCCR2A = 0;
TCCR2B = 0;
Expand Down Expand Up @@ -795,4 +879,4 @@ void TVout::tone(unsigned int frequency, unsigned long duration_ms) {
void TVout::noTone() {
TCCR2B = 0;
PORT_SND &= ~(_BV(SND_PIN)); //set pin 11 to 0
} // end of noTone
} // end of noTone
23 changes: 22 additions & 1 deletion TVout/spec/hardware_setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,27 @@
#define PORT_SND PORTB
#define DDR_SND DDRB
#define SND_PIN 4
#elif defined(__AVR_ATmega32U4__) // Modified for Arduino Leonardo
//video
#define PORT_VID PORTB
#define DDR_VID DDRB
#define VID_PIN 4 // 8
//sync
#define PORT_SYNC PORTB
#define DDR_SYNC DDRB
#define SYNC_PIN 5 // 9
//sound
#define PORT_SND PORTB
#define DDR_SND DDRB
#define SND_PIN 7 // 11
#define TCCR2A TCCR0A
#define TCCR2B TCCR0B
#define OCR2A OCR0A
#define OCR2B OCR0B
#define COM2A0 COM0A0
#define COM2A1 COM0A1
#define CS20 CS00
#define WGM21 WGM01
#endif

//automatic BST/BLD/ANDI macro definition
Expand Down Expand Up @@ -143,4 +164,4 @@
#define BST_HWS "bst r16,7\n\t"
#define ANDI_HWS "andi r16,0x7F\n"
#endif
#endif
#endif
1 change: 1 addition & 0 deletions TVoutfonts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Copy this folder to your Arduino libraries folder
Loading

0 comments on commit a3d3f57

Please sign in to comment.