https://youtu.be/wH6YXncjpPs
- the sound quality is still quite bad ( 6552 Hz) but this was a proof of concept, I will make better versions. Framerate is 13 fps.
- I will get back to the question of how to make your own videos like this later, as it requires several tools (ffmpg, imagemagick and 2 custom programs I made)
How to play it yourself:
1) The HEX for the player is in the attachment below
THERE IS NO GAMEBUINO MENU IN THIS DEMO, YOU HAVE TO USE "c" BUTTON DURING BOOT TO LOAD ANOTHER HEX AFTER THIS !!!
2) You can download the "U Can't Touch This" video file over here. Put the "VIDEO.JVD" file in the root of the SD card.
https://drive.google.com/file/d/0BweEjvtKj1KLb2IwQkxqTG05ems/view?usp=sharing
3) Here is the source code to the actual player on the Gamebuino, if you want to upload it from the Arduino IDE:
- Code: Select all
// Happy Birthday Gamebuino !
// Jonne Valola aka "Jonnection"
// Combines parts of Myndale's SD audio streaming demo
// and petit_fs lib demo
#include <TimerOne.h>
#include <petit_fatfs.h>
#define PLAYBACK_FREQ 6552 // was 6552
#define SPEAKER 3
#define BUFFER_SIZE 128
// GAMEBUINO DEFINED PINS
#define PIN_SCE A1 // PC 1 SCR ENABLE
#define PIN_RESET A0 // PC 0 SCR RESET
#define PIN_DC A2 // PC 2 SCR DC
#define PIN_SDIN 11 // PB 3 MOSI - data to screen
#define PIN_SCLK 13 // PB 5 SCK
#define PIN_BACKLIGHT 5 // PD 5 BACKLIGHT
#define PORT_SCLK PORTB
#define SCLK_BIT 5
#define PORT_SDIN PORTB
#define SDIN_BIT 3
#define LCD_C LOW
#define LCD_D HIGH
#define LCD_CMD 0
#define LCD_X 84
#define LCD_Y 48
byte buffer[LCD_X*LCD_Y/8];
unsigned char buffers[2][BUFFER_SIZE];
volatile int currentBuffer = 0;
volatile int bufindex = 0;
volatile boolean blit=false;
volatile unsigned char * currentPtr;
volatile unsigned char * endPtr;
const int chipSelect = 10;
WORD br;
void LcdClear(void)
{
for (int index = 0; index < LCD_X * LCD_Y / 8; index++)
{
LcdWrite(LCD_D, 0x00);
}
}
void LcdInitialise(void)
{
pinMode(PIN_SCE, OUTPUT);
pinMode(PIN_RESET, OUTPUT);
pinMode(PIN_DC, OUTPUT);
pinMode(PIN_SDIN, OUTPUT);
pinMode(PIN_SCLK, OUTPUT);
digitalWrite(PIN_RESET, LOW);
digitalWrite(PIN_RESET, HIGH);
LcdWrite( LCD_CMD, 0x21 ); // LCD Extended Commands.
LcdWrite( LCD_CMD, 0xB9 ); // Set LCD Vop (Contrast). //B1
LcdWrite( LCD_CMD, 0x04 ); // Set Temp coefficent. //0x04
LcdWrite( LCD_CMD, 0x14 ); // LCD bias mode 1:48. //0x13
LcdWrite( LCD_CMD, 0x0C ); // LCD in normal mode. 0x0d for inverse
LcdWrite(LCD_C, 0x20);
LcdWrite(LCD_C, 0x0C);
pinMode(5, OUTPUT); //backlight
digitalWrite(5, HIGH);
}
void LcdWrite(byte dc, byte data) {
digitalWrite(PIN_DC, dc); // select command or data mode
digitalWrite(PIN_SCE, LOW); // enable screen
digitalWrite(SS, HIGH); // disable SD
tx(data); // replace with hardware version from petit_fs demo
digitalWrite(PIN_SCE, HIGH); // disable screen
}
void gotoXY(int x, int y) {
LcdWrite( 0, 0x80 | x); // Column.
LcdWrite( 0, 0x40 | y); // Row.
}
void setup(void)
{
spi_init();
Serial.begin(9600);
Serial.println(F("Starting videoplayer"));
int a = PFFS.begin(10, rx, tx);
Serial.println(F("SD begin succeeded"));
int err = PFFS.open_file("VIDEO.JVD");
if (err) Serial.println(F("Video open failed"));
else Serial.println(F("Video open success"));
if (err==0) {
Serial.println(F("Data file opened"));
pf_read((void *)&buffers[0][0],BUFFER_SIZE,&br);
currentBuffer = 0;
currentPtr = buffers[currentBuffer];
endPtr = currentPtr + BUFFER_SIZE;
pinMode(SPEAKER, OUTPUT);
TCCR2B = (TCCR2B & 0b11111000) | 0x01; // set max PWM frequency
Timer1.initialize(1000000/PLAYBACK_FREQ);
Timer1.attachInterrupt(callback);
}
LcdInitialise();
gotoXY(0,0);
LcdClear();
}
void loop(void)
{
digitalWrite(SS, LOW);
pf_read((void *)&buffers[1][0],BUFFER_SIZE,&br);
digitalWrite(SS, HIGH);
while (currentBuffer != 1) if (blit) blitscreen();
digitalWrite(SS, LOW);
pf_read((void *)&buffers[0][0],BUFFER_SIZE,&br);
digitalWrite(SS, HIGH);
while (currentBuffer != 0) if (blit) blitscreen();
}
void callback()
{
buffer[bufindex] = (*currentPtr++);
bufindex++;
if (bufindex == 504) {
bufindex=0;
blit=true;
}
analogWrite(SPEAKER, (*currentPtr++));
if (currentPtr >= endPtr)
{
currentBuffer = 1-currentBuffer;
currentPtr = buffers[currentBuffer];
endPtr = currentPtr + BUFFER_SIZE;
}
}
byte rx()
{
// The SPI Data Register is a read/write register
// used for data transfer between the Register File and the SPI Shift Register.
// Writing to the register initiates data transmission. Reading the register causes the Shift Register receive buffer to be read.
SPDR = 0xFF; // dummy byte to initiate reading
// loop_until_bit_is_set is an AVR libc macro
// SPSR is SPI status register, SPIF is SPI interrupt flag, that is set after transmission is complete
loop_until_bit_is_set(SPSR, SPIF);
return SPDR; //return the SPDR (= value back from slave)
}
void tx(byte d)
{
SPDR = d;
loop_until_bit_is_set(SPSR, SPIF);
}
void spi_init()
{
pinMode(10, OUTPUT); // 10 = SS = Slave select of SD
pinMode(11, OUTPUT); // MOSI data to SD
pinMode(12, INPUT); // PB 4 - MISO data from SD
pinMode(13, OUTPUT); // SCLK
// SET HARDWARE SPI in Master & enabled
// default speed is Clock/4 = 4 Mhz which is maximum for nokia lcd
SPCR = _BV(MSTR) | _BV(SPE); // Master mode, SPI enable, clock speed MCU_XTAL/4
}
inline void blitscreen()
{
digitalWrite(PIN_DC, HIGH); // select data mode
digitalWrite(PIN_SCE, LOW); // enable screen
digitalWrite(SS, HIGH); // disable SD
for (int i = 0; i < 504; i++)
{
tx(buffer[i]);
}
digitalWrite(PIN_SCE, HIGH); // disable screen
blit=false;
}