I've managed to do a better video thanks to a tripod.
Progress:
- Now, it's possible to upload the FPGA configuration file via USB (VCOM port). It remains to store this file into the FLASH next to the LPC812, then the board will be ready at power on.
- I've made a little python application to do some tests with the board but also -and mainly- to upload image files to the embedded flash.
Here is the source C code for the animation. This code can easily be embedded in a small 8bit uC.
//Init LisaGlyph
for (uint32_t i=0; i<LISA_GLYPHS; i++)
GlyphLisa[i] = LISA_FL_START_ADDRESS + i * LISA_FL_STEP_ADDRESS;
//Init Lisa
for (uint32_t i=0; i<N_LISA; i++) {
Lisa[i].size = (SIZE_t){ LISA_SIZE_W, LISA_SIZE_H};
Lisa[i].pos.X = rand() % 1000;
Lisa[i].pos.Y = rand() % 500;
Lisa[i].inc.X = rand() % 10 + 0.5;
Lisa[i].inc.Y = i / 10.0 + 0.5;
Lisa[i].idxGlyph = 0;
}
//Init HomerGlyph
for (uint32_t i=0; i<HOMER_GLYPHS; i++)
GlyphHomer[i] = HOMER_FL_START_ADDRESS + i * HOMER_FL_STEP_ADDRESS;
//Init Homer
for (uint32_t i=0; i<N_HOMER; i++) {
Homer[i].size = (SIZE_t){ HOMER_SIZE_W, HOMER_SIZE_H};
Homer[i].pos.X = rand() % 1000;
Homer[i].pos.Y = rand() % 500;;
Homer[i].inc.X = rand() % 10;
Homer[i].inc.Y = i / 2.0;
Homer[i].idxGlyph = 0;
}
//Init BallGlyph
for (uint32_t i=0; i<BALL_GLYPHS; i++)
GlyphBall[i] = BALL_FL_START_ADDRESS + i * BALL_FL_STEP_ADDRESS;
Ball.size = (SIZE_t){ BALL_SIZE_W, BALL_SIZE_H};
Ball.pos.X = 500;
Ball.pos.Y = 100;
Ball.vit.X = 7.0;
Ball.acc.X = 0;
Ball.vit.Y = 0;
Ball.acc.Y = 1.5;
Ball.idxGlyph = 0;
GlyphMur = MUR_FL_START_ADDRESS;
Mur.size = (SIZE_t){ MUR_SIZE_W, MUR_SIZE_H};
Mur.pos.X = 500;
Mur.pos.Y = 719-512;
//Init display
GPUstorePalette(0);
GPUclipArea((COORD_t){0, 0}, (COORD_t){1279, 719});
while (1) {
GPUclearScreen(45);
for (uint32_t i=0; i<N_HOMER/2; i++)
GPUcopyBlob(
GlyphHomer[ Homer[i].idxGlyph ],
(COORD_t){ (int16_t)Homer[i].pos.X, (int16_t)Homer[i].pos.Y },
Homer[i].size,
0
);
for (uint32_t i=0; i<N_LISA/2; i++)
GPUcopyBlob(
GlyphLisa[ Lisa[i].idxGlyph ],
(COORD_t){ (int16_t)Lisa[i].pos.X, (int16_t)Lisa[i].pos.Y },
Lisa[i].size,
0
);
GPUcopyBlob(
GlyphMur,
(COORD_t){ (int16_t)Mur.pos.X, (int16_t)Mur.pos.Y },
Mur.size,
0
);
for (uint32_t i=N_LISA/2; i<N_LISA; i++)
GPUcopyBlob(
GlyphLisa[ Lisa[i].idxGlyph ],
(COORD_t){ (int16_t)Lisa[i].pos.X, (int16_t)Lisa[i].pos.Y },
Lisa[i].size,
0
);
for (uint32_t i=N_HOMER/2; i<N_HOMER; i++)
GPUcopyBlob(
GlyphHomer[ Homer[i].idxGlyph ],
(COORD_t){ (int16_t)Homer[i].pos.X, (int16_t)Homer[i].pos.Y },
Homer[i].size,
0
);
GPUcopyBlob(
GlyphBall[ Ball.idxGlyph ],
(COORD_t){ (int16_t)Ball.pos.X, (int16_t)Ball.pos.Y },
Ball.size,
0
);
GPUdrawLine((COORD_t){0, 0}, (COORD_t){ 1279, 0}, 15, 0);
GPUdrawLine((COORD_t){0, 0}, (COORD_t){ 0, 719}, 15, 0);
GPUdrawLine((COORD_t){1279, 0}, (COORD_t){ 1279, 719}, 15, 0);
GPUdrawLine((COORD_t){0, 719}, (COORD_t){ 1279, 719}, 15, 0);
for (uint32_t i=0; i<N_LISA; i++) {
Lisa[i].pos.X += Lisa[i].inc.X;
Lisa[i].pos.Y += Lisa[i].inc.Y;
if (Lisa[i].pos.X > SCR_W - Lisa[i].size.W || Lisa[i].pos.X < 0 ) {
Lisa[i].inc.X = - Lisa[i].inc.X;
Lisa[i].pos.X += Lisa[i].inc.X;
}
if (Lisa[i].pos.Y > SCR_H - Lisa[i].size.H || Lisa[i].pos.Y < 0 ) {
Lisa[i].inc.Y = - Lisa[i].inc.Y;
Lisa[i].pos.Y += Lisa[i].inc.Y;
}
Lisa[i].idxGlyph = ((uint16_t)(Lisa[i].pos.X/5)) % LISA_GLYPHS;
}
for (uint32_t i=0; i<N_HOMER; i++) {
Homer[i].pos.X += Homer[i].inc.X;
Homer[i].pos.Y += Homer[i].inc.Y;
if (Homer[i].pos.X > SCR_W - Homer[i].size.W || Homer[i].pos.X < 0 ) {
Homer[i].inc.X = - Homer[i].inc.X;
Homer[i].pos.X += Homer[i].inc.X;
}
if (Homer[i].pos.Y > SCR_H - Homer[i].size.H || Homer[i].pos.Y < 0 ) {
Homer[i].inc.Y = - Homer[i].inc.Y;
Homer[i].pos.Y += Homer[i].inc.Y;
}
Homer[i].idxGlyph = ((uint16_t)(Homer[i].pos.X/20)) % HOMER_GLYPHS;
}
Ball.vit.X += Ball.acc.X;
Ball.vit.Y += Ball.acc.Y;
Ball.pos.X += Ball.vit.X;
Ball.pos.Y += Ball.vit.Y;
if (Ball.pos.X > SCR_W - Ball.size.W || Ball.pos.X < 0 ) {
Ball.vit.X = - Ball.vit.X;
Ball.pos.X += Ball.vit.X;
}
if (Ball.pos.Y > SCR_H - Ball.size.H || Ball.pos.Y < 0 ) {
Ball.vit.Y = - Ball.vit.Y;
Ball.pos.Y += Ball.vit.Y;
}
Ball.idxGlyph = ((uint16_t)(Ball.pos.X/5)) % BALL_GLYPHS;
//Display it!
GPUswapBuffer();
}
Here is for example the C definition of a GPU function, Tx_Buff is a buffer whose the byte elements are sent to the SPI. Address is the blob address in the 8MBytes Flash connected to the FPGA.
Here I use DMA but simple transfert work also.
void GPUcopyBlob(uint32_t Address, COORD_t P1, SIZE_t Size, uint8_t operation)
{
Tx_Buf[0] = CMD_COPY_BLOB;
Tx_Buf[1] = 12; //DATA LENGTH
Tx_Buf[2] = Address >> 16; // FlashAddress MSB
Tx_Buf[3] = Address >> 8; // FlashAddress mSB
Tx_Buf[4] = Address; // FlashAddress LSB
Tx_Buf[5] = P1.X >> 8;
Tx_Buf[6] = P1.X;
Tx_Buf[7] = P1.Y >> 8;
Tx_Buf[8] = P1.Y;
Tx_Buf[9] = Size.W >> 8;
Tx_Buf[10] = Size.W;
Tx_Buf[11] = Size.H >> 8;
Tx_Buf[12] = Size.H;
Tx_Buf[13] = operation;
// Start transmission
SSP_DMA_Start(14, Tx_Buf, Rx_Buf);
}
I've made a SPI speed test, it's possible to go up to 32Mbits/s. That's well within the need. SPI is not the bottleneck here since the receive only commands, not big blobs of data.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.