.htotal = 800,
.vactive = 480,
- .vsync_start = 481,
- .vsync_end = 484,
- .vtotal = 497
+ .vsync_start = 490,
+ .vsync_end = 492,
+ .vtotal = 525,
};
#define mode vga_640x480x60
#define WIDTH_BYTES (AO_VGA_WIDTH >> 3)
-#define SCANOUT ((WIDTH_BYTES + 2) >> 1)
+#define SCANOUT ((WIDTH_BYTES+2) >> 1)
uint32_t ao_vga_fb[AO_VGA_STRIDE * AO_VGA_HEIGHT];
static uint32_t *scanline;
-#define DMA_INDEX STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX)
+#define DMA_INDEX STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX)
static int line;
static int vblank;
(0 << STM_DMA_CCR_TCIE) | \
(en << STM_DMA_CCR_EN))
-int vblank_off = 13;
+int vblank_off = 25;
void stm_tim2_isr(void)
{
/* Disable */
stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(0);
/* Reset DMA engine for the next scanline */
+ stm_dma.channel[DMA_INDEX].cmar = scanline;
stm_dma.channel[DMA_INDEX].cndtr = SCANOUT;
/* Enable */
stm_dma.channel[DMA_INDEX].ccr = DMA_CCR(1);
}
stm_tim2.sr = ~(1 << STM_TIM234_SR_CC2IF);
line = stm_tim3.cnt;
- if (vblank_off <= line && line < (AO_VGA_HEIGHT << 1) + vblank_off + 12) {
+ if (vblank_off <= line && line < (AO_VGA_HEIGHT << 1) + vblank_off) {
vblank = 0;
- if ((line - vblank_off) & 1)
+ if (((line - vblank_off) & 1) == 0)
scanline += AO_VGA_STRIDE;
} else {
- scanline = ao_vga_fb;
- vblank = 1;
+ if (!vblank) {
+ stm_systick_isr();
+ scanline = ao_vga_fb;
+ vblank = 1;
+ }
}
- stm_dma.channel[DMA_INDEX].cmar = scanline;
ao_arch_release_interrupts();
}
ao_text("UL",
ao_vga_fb,
AO_VGA_STRIDE,
- 0);
+ 1);
ao_text("BL",
ao_vga_fb + (240 - 7) * AO_VGA_STRIDE,
AO_VGA_STRIDE,
- 0);
+ 1);
+
+ memset(ao_vga_fb + 120 * AO_VGA_STRIDE, '\0', WIDTH_BYTES);
}
void
ao_vga_init(void)
{
- /* Initialize spi2 using PB15 for output */
+ /* Initialize spi1 using PB5 for output */
stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
- stm_ospeedr_set(&stm_gpiob, 15, STM_OSPEEDR_40MHz);
- stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
+ stm_ospeedr_set(&stm_gpiob, 5, STM_OSPEEDR_40MHz);
+ stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
/* turn on SPI */
- stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
- stm_spi2.cr1 = ((1 << STM_SPI_CR1_BIDIMODE) | /* Two wire mode */
+ stm_spi1.cr1 = ((1 << STM_SPI_CR1_BIDIMODE) | /* Two wire mode */
(1 << STM_SPI_CR1_BIDIOE) |
(0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
(0 << STM_SPI_CR1_CRCNEXT) |
(1 << STM_SPI_CR1_MSTR) |
(0 << STM_SPI_CR1_CPOL) | /* Format 0 */
(0 << STM_SPI_CR1_CPHA));
- stm_spi2.cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ stm_spi1.cr2 = ((0 << STM_SPI_CR2_TXEIE) |
(0 << STM_SPI_CR2_RXNEIE) |
(0 << STM_SPI_CR2_ERRIE) |
(0 << STM_SPI_CR2_SSOE) |
(1 << STM_SPI_CR2_TXDMAEN) |
(0 << STM_SPI_CR2_RXDMAEN));
- (void) stm_spi2.dr;
- (void) stm_spi2.sr;
+ (void) stm_spi1.dr;
+ (void) stm_spi1.sr;
- /* Grab the DMA channel for SPI2 MOSI */
- stm_dma.channel[DMA_INDEX].cpar = &stm_spi2.dr;
+ /* Grab the DMA channel for SPI1 MOSI */
+ stm_dma.channel[DMA_INDEX].cpar = &stm_spi1.dr;
stm_dma.channel[DMA_INDEX].cmar = ao_vga_fb;
/* hclock on timer 2 */
/* Channel 2 trigger scanout */
/* wait for the time to start scanout */
- stm_tim2.ccr2 = 90;
+ stm_tim2.ccr2 = mode.htotal - mode.hsync_end;
stm_tim2.ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
(STM_TIM234_CCMR1_OC2M_SET_HIGH_ON_MATCH << STM_TIM234_CCMR1_OC2M) |
stm_ospeedr_set(&stm_gpiob, 4, STM_OSPEEDR_40MHz);
stm_afr_set(&stm_gpiob, 4, STM_AFR_AF2);
-
/* Enable the scanline interrupt */
stm_nvic_set_priority(STM_ISR_TIM2_POS, 0);
stm_nvic_set_enable(STM_ISR_TIM2_POS);
#include <ao_boot.h>
#include <ao_vga.h>
+struct ao_task ball_task;
+
+#define BALL_WIDTH 5
+#define BALL_HEIGHT 5
+
+static int ball_x;
+static int ball_y;
+static int ball_dx, ball_dy;
+
+uint8_t ball_enable;
+
+void
+ao_ball(void)
+{
+ ball_dx = 1;
+ ball_dy = 1;
+ ball_x = 0;
+ ball_y = 0;
+ for (;;) {
+ while (!ball_enable)
+ ao_sleep(&ball_enable);
+ for (;;) {
+ ao_solid(AO_ALLONES,
+ AO_ALLONES,
+ ao_vga_fb + ball_y * AO_VGA_STRIDE,
+ AO_VGA_STRIDE,
+ ball_x,
+ BALL_WIDTH,
+ BALL_HEIGHT);
+ ao_delay(AO_MS_TO_TICKS(10));
+ ao_solid(AO_ALLONES,
+ AO_ALLONES,
+ ao_vga_fb + ball_y * AO_VGA_STRIDE,
+ AO_VGA_STRIDE,
+ ball_x,
+ BALL_WIDTH,
+ BALL_HEIGHT);
+ if (!ball_enable)
+ break;
+ ball_x += ball_dx;
+ ball_y += ball_dy;
+ if (ball_x + BALL_WIDTH > AO_VGA_WIDTH) {
+ ball_x = AO_VGA_WIDTH - BALL_WIDTH;
+ ball_dx = -ball_dx;
+ }
+ if (ball_x < 0) {
+ ball_x = -ball_x;
+ ball_dx = -ball_dx;
+ }
+ if (ball_y + BALL_HEIGHT > AO_VGA_HEIGHT) {
+ ball_y = AO_VGA_HEIGHT - BALL_HEIGHT;
+ ball_dy = -ball_dy;
+ }
+ if (ball_y < 0) {
+ ball_y = -ball_y;
+ ball_dy = -ball_dy;
+ }
+ }
+ }
+}
+
static void
ao_video_toggle(void)
{
ao_vga_enable(ao_cmd_lex_i);
}
+static void
+ao_ball_toggle(void)
+{
+ ao_cmd_decimal();
+ ball_enable = ao_cmd_lex_i;
+ ao_wakeup(&ball_enable);
+}
+
__code struct ao_cmds ao_demo_cmds[] = {
{ ao_video_toggle, "V\0Toggle video" },
+ { ao_ball_toggle, "B\0Toggle ball" },
{ 0, NULL }
};
ao_vga_init();
ao_usb_init();
+ ao_add_task(&ball_task, ao_ball, "ball");
ao_cmd_register(&ao_demo_cmds[0]);
ao_start_scheduler();