Demo of low res colour vga video for stm32f3 discovery board
Dependencies: STM32F3-Discovery-minimal
Fork of Space_Invaders_Demo by
Diff: video.c
- Revision:
- 3:93e488fbb8a2
- Parent:
- 1:1b37c4b989b4
- Child:
- 4:de45d218ed3c
--- a/video.c Tue May 17 23:53:10 2016 +0000 +++ b/video.c Wed May 16 02:39:14 2018 +0000 @@ -34,42 +34,57 @@ // #include "stm32f30x.h" #include "video.h" -//#include "stm32f3xx_hal_conf.h" -#define HTOTAL (VID_HSIZE+2) /* Total bytes to send through SPI */ +#define HTOTAL (VID_HSIZE+3) /* Total bytes to send */ -__attribute__ ((aligned (4))) u8 volatile fba[VID_VSIZE*HTOTAL*2]; /* Frame buffer */ +__attribute__ ((aligned (4))) u8 volatile fba[VID_VSIZE*HTOTAL]; /* Frame buffer */ -u8 volatile *fb[VID_VSIZE*2]; +__attribute__ ((section ("ccmram"))) u8 volatile *fb[VID_VSIZE]; int fboffset=0; static volatile u16 vline = 0; /* The current line being drawn */ -static volatile u32 vflag = 0; /* When 1, the SPI DMA request can draw on the screen */ +static volatile u32 vflag = 0; /* When 1, the DMA request can draw on the screen */ static volatile u32 vdraw = 0; /* Used to increment vline every 3 drawn lines */ -void TIMER_Configuration(void) -{ - GPIO_InitTypeDef GPIO_InitStructure; - NVIC_InitTypeDef nvic; - TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; - TIM_OCInitTypeDef TIM_OCInitStructure; +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 +#define GPIO_MODE_AF 2 + +#define GPIO_NO_PULL 0 +#define GPIO_PULL_UP 1 +#define GPIO_PULL_DOWN 2 + +#define GPIO_OUTPUT_PUSH_PULL 0 + + +#define GPIO_SPEED_MEDIUM 1 +#define GPIO_SPEED_LOW 0 +#define GPIO_SPEED_HIGH 3 + + +void gpio_set_mode(GPIO_TypeDef *g,int n,int mode) { + n=n<<1; + g->MODER = (g->MODER & ~(3<<n)) | (mode<<n); +} + +void gpio_set_af(GPIO_TypeDef *g,int n,int af, int otype, int pupd, int speed) { + int reg=n>>3; + int pos=(n&7)*4; + g->AFR[reg] = (g->AFR[reg] & ~(0xf<<pos)) | (af<<pos); // alt func + pos=(n<<1); + g->OSPEEDR = (g->OSPEEDR & ~(3<<pos)) | (speed<<pos); + g->OTYPER = (g->OTYPER & ~(1<<n)) | (otype<<n); + gpio_set_mode(g,n,GPIO_MODE_AF); + g->PUPDR = (g->PUPDR & ~(3<<pos)) | (pupd<<pos); +} + +void TIMER_Configuration(void) { u32 TimerPeriod = 0; u16 Channel1Pulse = 0, Channel2Pulse = 0, Channel3Pulse = 0; - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_8; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; - GPIO_Init(GPIOA, &GPIO_InitStructure); + gpio_set_af(GPIOA,1,1,GPIO_OUTPUT_PUSH_PULL, GPIO_NO_PULL, GPIO_SPEED_LOW); + gpio_set_af(GPIOA,8,6,GPIO_OUTPUT_PUSH_PULL, GPIO_NO_PULL, GPIO_SPEED_LOW); - GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_6); // TIM1_CH1 - GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_1); // TIM2_CH2 - - - - - - /* SVGA 800x600 @ 56 Hz Vertical refresh 35.15625 kHz @@ -112,34 +127,37 @@ Channel1Pulse = 144; /* HSYNC */ Channel2Pulse = 364; /* HSYNC + BACK PORCH */ - TIM_TimeBaseStructure.TIM_Prescaler = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Period = TimerPeriod; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; - TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); - - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; - TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; - TIM_OCInitStructure.TIM_Pulse = Channel1Pulse; - TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; - TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; - TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; - TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set; - - TIM_OC1Init(TIM1, &TIM_OCInitStructure); + TIM1->CR1 &= ~TIM_CR1_CEN; + TIM1->PSC=0; + TIM1->ARR=TimerPeriod; + TIM1->CNT=0; - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive; - TIM_OCInitStructure.TIM_Pulse = Channel2Pulse; - TIM_OC2Init(TIM1, &TIM_OCInitStructure); - - /* TIM1 counter enable and output enable */ - TIM_CtrlPWMOutputs(TIM1, ENABLE); - - /* Select TIM1 as Master */ - TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable); - TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); + // disable Capture and Compare 1 and 2 + TIM1->CCER &= ~(TIM_CCER_CC1E | TIM_CCER_CC2E); + // set output compare 1 to PWM mode with preload + TIM1->CCMR1 = (TIM1->CCMR1 & ~(TIM_CCMR1_OC1M | TIM_CCMR1_CC1S)) | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; + TIM1->CCR1=Channel1Pulse; + TIM1->CCR2=Channel2Pulse; + TIM1->CCR2 |= TIM_CR2_OIS1; // output idle state set + // enable Capture and Compare 1 + TIM1->CCER |= TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC1P | TIM_CCER_CC2P; // output polarity low + // main output enable + TIM1->BDTR |= TIM_BDTR_MOE; + + TIM1->SMCR |= TIM_SMCR_MSM; // master slave mode + + TIM1->CR2 = (TIM1->CR2 & ~TIM_CR2_MMS) | TIM_CR2_MMS_1;// TIM_TRGOSource_Update mode + + TIM8->CR1 &= ~TIM_CR1_CEN; + TIM8->PSC=2; + TIM8->ARR=2; + TIM8->CNT=0; + //TIM16->CR1 |= TIM_CR1_OPM; + + TIM8->DIER |= TIM_DIER_UDE; + TIM8->SMCR=TIM8->SMCR & ~(TIM_SMCR_SMS | TIM_SMCR_TS) | 4 ; + //TIM16->SMCR |= TIM_SMCR_MSM; + //TIM16->CR2 = (TIM16->CR2 & ~TIM_CR2_MMS) | TIM_CR2_MMS_1;// TIM_TRGOSource_Update mode /* Vertical timing @@ -159,135 +177,85 @@ /* VSYNC (TIM2_CH2) and VSYNC_BACKPORCH (TIM2_CH3) */ /* Channel 2 and 3 Configuration in PWM mode */ - TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Gated); - TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0); + TIM2->SMCR=TIM2->SMCR & ~(TIM_SMCR_SMS | TIM_SMCR_TS) | 5 ;// gated slave mode trigger source 0 + TimerPeriod = 625; /* Vertical lines */ Channel2Pulse = 2; /* Sync pulse */ Channel3Pulse = 24; /* Sync pulse + Back porch */ - TIM_TimeBaseStructure.TIM_Prescaler = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Period = TimerPeriod; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; - TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); - - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; - TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; - TIM_OCInitStructure.TIM_Pulse = Channel2Pulse; - TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; - TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; - TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; - TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set; - TIM_OC2Init(TIM2, &TIM_OCInitStructure); - - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive; - TIM_OCInitStructure.TIM_Pulse = Channel3Pulse; - TIM_OC3Init(TIM2, &TIM_OCInitStructure); + TIM2->CR1 &= ~TIM_CR1_CEN; + TIM2->PSC=0; + TIM2->ARR=TimerPeriod; + TIM2->CNT=0; - /* TIM2 counter enable and output enable */ - TIM_CtrlPWMOutputs(TIM2, ENABLE); - - /* Interrupt TIM2 */ - nvic.NVIC_IRQChannel = TIM2_IRQn; - nvic.NVIC_IRQChannelPreemptionPriority = 1; - nvic.NVIC_IRQChannelSubPriority = 0; - nvic.NVIC_IRQChannelCmd = ENABLE; - - NVIC_Init(&nvic); - TIM_ITConfig(TIM2, TIM_IT_CC3, ENABLE); + // disable Capture and Compare 2 and 3 + TIM2->CCER &= ~(TIM_CCER_CC2E | TIM_CCER_CC3E); + // set output compare 1 to PWM mode with preload + TIM2->CCMR1 = (TIM2->CCMR1 & ~(TIM_CCMR1_OC2M | TIM_CCMR1_CC2S)) | TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1; + TIM2->CCR2=Channel2Pulse; + TIM2->CCR3=Channel3Pulse; + +// TIM2->CCR2 |= TIM_CR2_OIS1; // output idle state set + // enable Capture and Compare 2 and 3 + TIM2->CCER |= TIM_CCER_CC2E | TIM_CCER_CC3E | TIM_CCER_CC1P | TIM_CCER_CC2P; // output polarity low + + // main output enable + TIM2->BDTR |= TIM_BDTR_MOE; - /* Interrupt TIM1 */ - nvic.NVIC_IRQChannel = TIM1_CC_IRQn; - nvic.NVIC_IRQChannelPreemptionPriority = 1; - nvic.NVIC_IRQChannelSubPriority = 0; - nvic.NVIC_IRQChannelCmd = ENABLE; + NVIC->IP[TIM2_IRQn]=10; // Interrupt Priority, lower is higher priority + NVIC->ISER[TIM2_IRQn >> 0x05] = 1 << (TIM2_IRQn & 0x1F); // Interrupt enable + + TIM2->DIER |= TIM_DIER_CC3IE; + + NVIC->IP[TIM1_CC_IRQn]=1; // Interrupt Priority, lower is higher priority + NVIC->ISER[TIM1_CC_IRQn >> 0x05] = 1 << (TIM1_CC_IRQn & 0x1F); // Interrupt enable - NVIC_Init(&nvic); - TIM_ITConfig(TIM1, TIM_IT_CC2, ENABLE); - -// GPIOE->ODR=0; - TIM_Cmd(TIM2, ENABLE); - TIM_Cmd(TIM1, ENABLE); + TIM1->DIER |= TIM_DIER_CC2IE; + + TIM2->CR1 |= TIM_CR1_CEN; + TIM1->CR1 |= TIM_CR1_CEN; } -void SPI_Configuration(void) -{ - NVIC_InitTypeDef nvic; - SPI_InitTypeDef SPI_InitStructure; - DMA_InitTypeDef DMA_InitStructure; - GPIO_InitTypeDef GPIO_InitStructure; +void DMA_Configuration(void) { + //gpio_set_af(GPIOA,7,5,GPIO_OUTPUT_PUSH_PULL, GPIO_NO_PULL, GPIO_SPEED_HIGH); + + GPIOD->PUPDR = (GPIOD->PUPDR & ~0xffff) | 0;//xaaaa; // pull down (1010) + GPIOD->OSPEEDR = (GPIOD->OSPEEDR & ~(0xffff)) | 0xffff; + - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; - GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; - GPIO_Init(GPIOA, &GPIO_InitStructure); - - GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_5); // SPI1_MOSI - - SPI_Cmd(SPI1, DISABLE); - DMA_DeInit(DMA1_Channel3); - - DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR; - DMA_InitStructure.DMA_MemoryBaseAddr = (u32) fba+fboffset; - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; - DMA_InitStructure.DMA_BufferSize = HTOTAL; - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; - DMA_InitStructure.DMA_Priority = DMA_Priority_Low; - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; - DMA_Init(DMA1_Channel3, &DMA_InitStructure); - - SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; - SPI_InitStructure.SPI_Mode = SPI_Mode_Master; - SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; - SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; - SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; - SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; - SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; - SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; - SPI_InitStructure.SPI_CRCPolynomial = 7; - SPI_Init(SPI1, &SPI_InitStructure); + RCC->AHBENR |= RCC_AHBENR_DMA2EN; + // direction = peripheral dest, memory inc, peripheral size=halfword, memory size=byte, priority level=high, transmission complete interrupt enabled + DMA2_Channel1->CCR = DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_PL_0 | DMA_CCR_TCIE; +// DMA1_Channel3->CCR = DMA_CCR_PINC | DMA_CCR_PL_1 | DMA_CCR_PL_0 | DMA_CCR_TCIE | DMA_CCR_MEM2MEM; + // bytes to transfer + DMA2_Channel1->CNDTR = HTOTAL*2; + // peripheral address + DMA2_Channel1->CPAR =(uint32_t) &GPIOD->ODR; + // memory address + DMA2_Channel1->CMAR =(u32) fba+fboffset; + // enable CC DMA for TIM16 + // TIM16->DIER |= TIM_DIER_CC1DE; + // configure NVIC + NVIC->IP[DMA2_Channel1_IRQn]=16; // Interrupt Priority, lower is higher priority + NVIC->ISER[DMA2_Channel1_IRQn >> 0x05] = 1 << (DMA2_Channel1_IRQn & 0x1F); // Interrupt enable - SPI_CalculateCRC(SPI1, DISABLE); - SPI_Cmd(SPI1, ENABLE); - - SPI1->CR2 |= SPI_I2S_DMAReq_Tx; - - nvic.NVIC_IRQChannel = DMA1_Channel3_IRQn; - nvic.NVIC_IRQChannelPreemptionPriority = 0; - nvic.NVIC_IRQChannelSubPriority = 0; - nvic.NVIC_IRQChannelCmd = ENABLE; - NVIC_Init(&nvic); - - DMA1_Channel3->CCR &= ~1; - DMA1_Channel3->CNDTR = HTOTAL; - DMA1_Channel3->CMAR = (u32) fba+fboffset; - - DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE); } //***************************************************************************** // This irq is generated at the end of the horizontal back porch. // Test if inside a valid vertical start frame (vflag variable), -// and start the DMA to output a single frame buffer line through the SPI device. +// and start the DMA to output a single frame buffer line through the GPIO device. //***************************************************************************** //__attribute__((interrupt)) -__attribute__ ((section ("ccmram"))) void TIM1_CC_IRQHandler(void) -{ - if (vflag) - { - DMA1_Channel3->CCR = 0x3093; +__attribute__ ((section ("ccmram"))) void TIM1_CC_IRQHandler(void) { + if (vflag) { + DMA2_Channel1->CCR = DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_PL_0 | DMA_CCR_TCIE | DMA_CCR_EN;;// 0x3093; +// TIM8->CNT=0;//TIM8->ARR; + TIM8->CR1 |= TIM_CR1_CEN; } TIM1->SR = 0xFFFB; //~TIM_IT_CC2; -// GPIOE->ODR ^= 0x2000; } //***************************************************************************** @@ -295,12 +263,13 @@ // Sets the 'vflag' variable to 1 (valid vertical frame). //***************************************************************************** //__attribute__((interrupt)) -__attribute__ ((section ("ccmram"))) void TIM2_IRQHandler(void) -{ -// GPIOE->ODR = 0x100; +__attribute__ ((section ("ccmram"))) void TIM2_IRQHandler(void) { vflag = 1; TIM2->SR = 0xFFF7; //~TIM_IT_CC3; -// GPIOE->ODR ^= 0x04000; +// DMA2_Channel1->CCR = DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_PL_0 | DMA_CCR_TCIE | DMA_CCR_EN;;// 0x3093; + // TIM8->CNT=0; + TIM8->CR1 |= TIM_CR1_CEN; + } //***************************************************************************** @@ -309,53 +278,56 @@ // in the DMA register. //***************************************************************************** //__attribute__((interrupt)) -__attribute__ ((section ("ccmram"))) void DMA1_Channel3_IRQHandler(void) -{ -// GPIOE->ODR = 0x200; - DMA1->IFCR = DMA1_IT_TC3; - DMA1_Channel3->CCR = 0x92;// | (1<<10) | (1<<8); - DMA1_Channel3->CNDTR = HTOTAL; +__attribute__ ((section ("ccmram"))) void DMA2_Channel1_IRQHandler(void) { + DMA2->IFCR = DMA_ISR_TCIF1; + DMA2_Channel1->CCR = DMA_CCR_DIR | DMA_CCR_MINC | DMA_CCR_PL_1 | DMA_CCR_PL_0 | DMA_CCR_TCIE;// 0x3093; 0x92;// | (1<<10) | (1<<8); + DMA2_Channel1->CNDTR = HTOTAL; + TIM8->CR1 &= ~TIM_CR1_CEN; vdraw++; - - if (vdraw == 2) - { + if (vdraw == 4) { vdraw = 0; - vline++; - - if (vline == VID_VSIZE) - { + if (vline == VID_VSIZE) { vdraw = vline = vflag = 0; - DMA1_Channel3->CMAR = (u32) fba+fboffset; + DMA2_Channel1->CMAR = (u32) fba+fboffset; } else { - DMA1_Channel3->CMAR += HTOTAL; + DMA2_Channel1->CMAR += HTOTAL; } } -// GPIOE->ODR ^= 0x8000; +} +__attribute__ ((section ("ccmram"))) void vidNextBuffer(void) { + char *fp=(unsigned *)fb[0]; + for(int i=0;i<VID_VSIZE*HTOTAL;i++) + *fp++=(*fp>>4);//&0xf0f0f0f; } -void vidClearScreen(void) -{ +__attribute__ ((section ("ccmram"))) void waitForRefresh(void) { + while(vflag) __wfi(); +} +void vidClearScreen(void) { u16 x, y; - for (y = 0; y < VID_VSIZE*2; y++) - { -// GPIOE->ODR=(y<<8); -// for(x=0;x<1000;x++); - for (x = 0; x < HTOTAL; x++) - { + for (y = 0; y < VID_VSIZE; y++) { + for (x = 0; x < HTOTAL; x++) { fba[y*HTOTAL+x] = 0; } } } -void vidInit(void) -{ +void vidDot(int x, int y, int col) { + fb[y][x]=col; +} + +void vidLine(int x, int y, int col) { + fb[y][x]=col; +} + +void vidInit(void) { int i; - SPI_Configuration(); + DMA_Configuration(); TIMER_Configuration(); - for(i=0;i<VID_VSIZE*2;i++) + for(i=0;i<VID_VSIZE;i++) fb[i]=fba+i*HTOTAL; vidClearScreen(); }