dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_video.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  */
30 
31 #include "pios_config.h"
32 
33 #if defined(PIOS_INCLUDE_VIDEO)
34 
35 #include "pios.h"
36 #include "pios_video.h"
37 #include "pios_semaphore.h"
38 
39 // How many frames until we redraw
40 #define VSYNC_REDRAW_CNT 2
41 
42 #ifndef PIOS_VIDEO_HSYNC_OFFSET
43 #define PIOS_VIDEO_HSYNC_OFFSET 0
44 #endif
45 
47 
48 static const struct pios_video_type_boundary pios_video_type_boundary_ntsc = {
49  .graphics_right = 351, // must be: graphics_width_real - 1
50  .graphics_bottom = 239, // must be: graphics_height_real - 1
51 };
52 
53 static const struct pios_video_type_boundary pios_video_type_boundary_pal = {
54  .graphics_right = 359, // must be: graphics_width_real - 1
55  .graphics_bottom = 265, // must be: graphics_height_real - 1
56 };
57 
58 static const struct pios_video_type_cfg pios_video_type_cfg_ntsc = {
59  .graphics_height_real = 240, // Real visible lines
60  .graphics_column_start = 103, // First visible OSD column (after Hsync)
61  .graphics_line_start = 19, // First visible OSD line
62  .dma_buffer_length = 45, // DMA buffer length in bytes (graphics_right / 8 + 1)
63  .period = 24,
64  .dc = 12,
65 };
66 
67 static const struct pios_video_type_cfg pios_video_type_cfg_pal = {
68  .graphics_height_real = 266, // Real visible lines
69  .graphics_column_start = 149, // First visible OSD column (after Hsync)
70  .graphics_line_start = 28, // First visible OSD line
71  .dma_buffer_length = 46, // DMA buffer length in bytes ((graphics_right + 1) / 8 + 1)
72  .period = 22,
73  .dc = 11,
74 };
75 
76 // Allocate buffers.
77 // Must be allocated in one block, so it is in a struct.
78 struct _buffers {
79  uint8_t buffer0_level[BUFFER_HEIGHT * BUFFER_WIDTH];
80  uint8_t buffer0_mask[BUFFER_HEIGHT * BUFFER_WIDTH];
81  uint8_t buffer1_level[BUFFER_HEIGHT * BUFFER_WIDTH];
82  uint8_t buffer1_mask[BUFFER_HEIGHT * BUFFER_WIDTH];
83 } buffers;
84 
85 // Remove the struct definition (makes it easier to write for).
86 #define buffer0_level (buffers.buffer0_level)
87 #define buffer0_mask (buffers.buffer0_mask)
88 #define buffer1_level (buffers.buffer1_level)
89 #define buffer1_mask (buffers.buffer1_mask)
90 
91 // Pointers to each of these buffers.
92 uint8_t *draw_buffer_level;
93 uint8_t *draw_buffer_mask;
94 uint8_t *disp_buffer_level;
95 uint8_t *disp_buffer_mask;
96 
97 volatile int16_t active_line = 10000;
98 
99 const struct pios_video_type_boundary *pios_video_type_boundary_act = &pios_video_type_boundary_pal;
100 
101 
102 // Private variables
103 static int8_t x_offset = 0;
104 static int8_t x_offset_new = 0;
105 static int8_t y_offset = 0;
106 static uint16_t arr_value;
107 static const struct pios_video_cfg *dev_cfg = NULL;
108 static uint16_t num_video_lines = 0;
109 static enum pios_video_system video_system_act = PIOS_VIDEO_SYSTEM_NONE;
110 static const struct pios_video_type_cfg *pios_video_type_cfg_act = &pios_video_type_cfg_pal;
111 
112 // Private functions
113 static void swap_buffers();
114 static void prepare_line(int16_t line);
115 static void vid_disable_spis();
116 
120 bool PIOS_Vsync_ISR()
121 {
122  static uint16_t Vsync_update = 0;
123 
124  // discard spurious vsync pulses (due to improper grounding), so we don't overload the CPU
125  if (active_line < (pios_video_type_cfg_ntsc.graphics_height_real / 2)) {
126  active_line = - (pios_video_type_cfg_act->graphics_line_start + y_offset);
127  return false;
128  }
129 
130  // Update the number of video lines
131  num_video_lines = active_line +
132  (pios_video_type_cfg_act->graphics_line_start + y_offset);
133 
134  enum pios_video_system video_system_tmp;
135 
136  static uint8_t mode_hysteresis = 0;
137 
138  // check video type
139  if (num_video_lines > VIDEO_TYPE_PAL_ROWS) {
140  video_system_tmp = PIOS_VIDEO_SYSTEM_PAL;
141  } else {
142  video_system_tmp = PIOS_VIDEO_SYSTEM_NTSC;
143  }
144 
145  // if video type has changed set new active values
146  if ((video_system_act != video_system_tmp) && (mode_hysteresis++ > 10)) {
147  video_system_act = video_system_tmp;
148  if (video_system_act == PIOS_VIDEO_SYSTEM_NTSC) {
149  pios_video_type_boundary_act = &pios_video_type_boundary_ntsc;
150  pios_video_type_cfg_act = &pios_video_type_cfg_ntsc;
151  } else {
152  pios_video_type_boundary_act = &pios_video_type_boundary_pal;
153  pios_video_type_cfg_act = &pios_video_type_cfg_pal;
154  }
155 
156  if (dev_cfg->pixel_timer.timer == TIM9) { // XXX or other fast timers
157  dev_cfg->pixel_timer.timer->CCR1 = pios_video_type_cfg_act->dc;
158  dev_cfg->pixel_timer.timer->ARR = pios_video_type_cfg_act->period - 1;
159  } else {
160  dev_cfg->pixel_timer.timer->CCR1 = pios_video_type_cfg_act->dc / 2;
161  dev_cfg->pixel_timer.timer->ARR = pios_video_type_cfg_act->period / 2 - 1;
162  }
163 
164  x_offset = -100; /* Force recalc */
165  } else if (video_system_act == video_system_tmp) {
166  mode_hysteresis = 0;
167  }
168 
169  if (x_offset != x_offset_new)
170  {
171  x_offset = x_offset_new;
172 
173  arr_value = (pios_video_type_cfg_act->dc * (pios_video_type_cfg_act->graphics_column_start + x_offset)) / 2;
174  }
175 
176  bool woken = false;
177 
178  // Every VSYNC_REDRAW_CNT field: swap buffers and trigger redraw
179  if (++Vsync_update >= VSYNC_REDRAW_CNT) {
180  Vsync_update = 0;
181  swap_buffers();
182 
183  PIOS_Semaphore_Give_FromISR(onScreenDisplaySemaphore, &woken);
184  }
185 
186  // Get ready for the first line
187  active_line = - (pios_video_type_cfg_act->graphics_line_start + y_offset);
188 
189 #ifdef PIOS_INCLUDE_WS2811
190 #ifdef SYSTEMMOD_RGBLED_VIDEO_HACK
192 #endif
193 #endif
194 
195  return woken;
196 }
197 
198 
199 void PIOS_Line_ISR(void);
200 void TIM2_IRQHandler(void) __attribute__((alias("PIOS_Line_ISR")));
201 
205 void PIOS_Line_ISR(void)
206 {
207  /* What this looks like:
208  * - Vsync int sets active line to a negative value for the number of
209  * ignored lines.
210  * - Line ISR increments it each time we're called; when it reaches 0,
211  * we disable ourselves and cue the DMA engine. DMA engine is
212  * responsible for counting lines.
213  * - When DMA engine is done, it re-enables us and we keep counting.
214  */
215  if(TIM_GetITStatus(dev_cfg->hsync_capture.timer, TIM_IT_Update))
216  {
217  TIM_ClearITPendingBit(dev_cfg->hsync_capture.timer,
218  TIM_IT_Update);
219 
220  if (active_line > 10000) {
221  // Don't wrap.
222  return;
223  }
224 
225  if (active_line == 0) {
226  dev_cfg->hsync_capture.timer->ARR = arr_value;
227 
228  // Prepare the first line
229  prepare_line(0);
230 
231  return;
232  }
233 
234  active_line++;
235  }
236 }
237 
238 void PIOS_VIDEO_DMA_Handler(void);
239 void DMA2_Stream3_IRQHandler(void) __attribute__((alias("PIOS_VIDEO_DMA_Handler")));
240 void DMA1_Stream4_IRQHandler(void) __attribute__((alias("PIOS_VIDEO_DMA_Handler")));
241 
242 static void vid_disable_spis()
243 {
244  // Disable the SPI, makes sure the pins are LOW
245  dev_cfg->mask.regs->CR1 &= (uint16_t)~SPI_CR1_SPE;
246  dev_cfg->level.regs->CR1 &= (uint16_t)~SPI_CR1_SPE;
247 
248  // Stop pixel timer
249  dev_cfg->pixel_timer.timer->CR1 &= (uint16_t) ~TIM_CR1_CEN;
250 }
251 
257 void PIOS_VIDEO_DMA_Handler(void)
258 {
259  // Handle flags from DMA stream channel
260  if ((dev_cfg->mask_dma->LISR & DMA_FLAG_TCIF3) && (dev_cfg->level_dma->HISR & DMA_FLAG_TCIF4)) {
261  // Clear the DMA interrupt flags
262  dev_cfg->mask_dma->LIFCR |= DMA_FLAG_TCIF3;
263  dev_cfg->level_dma->HIFCR |= DMA_FLAG_TCIF4;
264 
265  dev_cfg->mask.dma.tx.channel->CR &= ~(uint32_t)DMA_SxCR_EN;
266  dev_cfg->level.dma.tx.channel->CR &= ~(uint32_t)DMA_SxCR_EN;
267 
268  /* Wait for SPIs to be done */
269  while ((dev_cfg->level.regs->SR & SPI_I2S_FLAG_TXE) == 0);
270  while (dev_cfg->level.regs->SR & SPI_I2S_FLAG_BSY);
271 
272  // Disable SSEL to control phase
273  dev_cfg->level.regs->CR1 |= SPI_CR1_SSI;
274 
275  while ((dev_cfg->mask.regs->SR & SPI_I2S_FLAG_TXE) == 0);
276  while (dev_cfg->mask.regs->SR & SPI_I2S_FLAG_BSY);
277 
278  dev_cfg->mask.regs->CR1 |= SPI_CR1_SSI;
279 
280  vid_disable_spis();
281 
282  int16_t line = active_line;
283 
284  if ((line >= 0) && (line < pios_video_type_cfg_act->graphics_height_real)) { // lines existing
285  prepare_line(line);
286  } else { // last line completed
287  TIM_ITConfig(dev_cfg->hsync_capture.timer, TIM_IT_Update, ENABLE);
288  // Disable the pixel timer slave mode configuration
289  dev_cfg->pixel_timer.timer->SMCR &= (uint16_t) ~TIM_SMCR_SMS;
290 
291  // Hard-limit how quickly line interrupts can show up.
292  // 84MHz / 3600 = 24KHz; PAL and NTSC are ~15.5KHz
293  dev_cfg->hsync_capture.timer->ARR = 3500;
294  }
295  }
296 }
297 
303 static inline void prepare_line(int16_t line)
304 {
305  TIM_ITConfig(dev_cfg->hsync_capture.timer, TIM_IT_Update, DISABLE);
306 
307  uint32_t buf_offset = line * BUFFER_WIDTH;
308 
309  // Set initial value
310  dev_cfg->pixel_timer.timer->CNT = 0;
311 
312  // Reset the SMS bits
313  dev_cfg->pixel_timer.timer->SMCR &= (uint16_t) ~TIM_SMCR_SMS;
314  dev_cfg->pixel_timer.timer->SMCR |= TIM_SlaveMode_Trigger;
315 
316  // Load new line
317  dev_cfg->mask.dma.tx.channel->M0AR = (uint32_t)&disp_buffer_mask[buf_offset];
318  dev_cfg->level.dma.tx.channel->M0AR = (uint32_t)&disp_buffer_level[buf_offset];
319  // Set length
320  dev_cfg->mask.dma.tx.channel->NDTR = (uint16_t)pios_video_type_cfg_act->dma_buffer_length;
321  dev_cfg->level.dma.tx.channel->NDTR = (uint16_t)pios_video_type_cfg_act->dma_buffer_length;
322 
323  // Enable SPI
324  dev_cfg->mask.regs->CR1 |= SPI_CR1_SPE;
325  dev_cfg->level.regs->CR1 |= SPI_CR1_SPE;
326 
327  // Enable DMA
328  dev_cfg->mask.dma.tx.channel->CR |= (uint32_t)DMA_SxCR_EN;
329  dev_cfg->level.dma.tx.channel->CR |= (uint32_t)DMA_SxCR_EN;
330 
331  // Advance line counter
332  active_line++;
333 
334  dev_cfg->mask.regs->CR1 &= (uint16_t) ~ SPI_CR1_SSI;
335  dev_cfg->level.regs->CR1 &= (uint16_t) ~ SPI_CR1_SSI;
336 }
337 
338 
344 static void swap_buffers()
345 {
346  // While we could use XOR swap this is more reliable and
347  // dependable and it's only called a few times per second.
348  // Many compilers should optimize these to EXCH instructions.
349  uint8_t *tmp;
350 
351  SWAP_BUFFS(tmp, disp_buffer_mask, draw_buffer_mask);
352  SWAP_BUFFS(tmp, disp_buffer_level, draw_buffer_level);
353 }
354 
358 void PIOS_Video_Init(const struct pios_video_cfg *cfg)
359 {
360  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
361  dev_cfg = cfg; // store config before enabling interrupt
362 
363  // This code currently only works with SPI1 and SPI2, catch misconfigurations here
364  if ((cfg->mask.regs != SPI1) && (cfg->mask.regs != SPI2))
365  PIOS_Assert(0);
366 
367  if ((cfg->level.regs != SPI1) && (cfg->level.regs != SPI2))
368  PIOS_Assert(0);
369 
370  // SPI for maskbuffer
371  GPIO_Init(cfg->mask.sclk.gpio, (GPIO_InitTypeDef *)&(cfg->mask.sclk.init));
372  GPIO_Init(cfg->mask.miso.gpio, (GPIO_InitTypeDef *)&(cfg->mask.miso.init));
373  if (cfg->mask.remap) {
374  GPIO_PinAFConfig(cfg->mask.sclk.gpio, __builtin_ctz(cfg->mask.sclk.init.GPIO_Pin), cfg->mask.remap);
375  GPIO_PinAFConfig(cfg->mask.miso.gpio, __builtin_ctz(cfg->mask.miso.init.GPIO_Pin), cfg->mask.remap);
376  }
377 
378  // SPI for levelbuffer
379  GPIO_Init(cfg->level.sclk.gpio, (GPIO_InitTypeDef *)&(cfg->level.sclk.init));
380  GPIO_Init(cfg->level.miso.gpio, (GPIO_InitTypeDef *)&(cfg->level.miso.init));
381  if (cfg->level.remap) {
382  GPIO_PinAFConfig(cfg->level.sclk.gpio, __builtin_ctz(cfg->level.sclk.init.GPIO_Pin), cfg->level.remap);
383  GPIO_PinAFConfig(cfg->level.miso.gpio, __builtin_ctz(cfg->level.miso.init.GPIO_Pin), cfg->level.remap);
384  }
385 
386  // HSYNC captrue timer: Start counting at HSYNC and start pixel timer after at correct x-position
387  GPIO_Init(cfg->hsync_capture.pin.gpio, (GPIO_InitTypeDef *)&(cfg->hsync_capture.pin.init));
388  if (cfg->hsync_capture.remap) {
389  GPIO_PinAFConfig(cfg->hsync_capture.pin.gpio, __builtin_ctz(cfg->hsync_capture.pin.init.GPIO_Pin), cfg->hsync_capture.remap);
390  }
391 
392  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
393  TIM_TimeBaseStructure.TIM_Period = pios_video_type_cfg_act->dc * (pios_video_type_cfg_act->graphics_column_start + x_offset) / 2;
394  TIM_TimeBaseStructure.TIM_Prescaler = 0;
395  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
396  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
397  TIM_TimeBaseInit(cfg->hsync_capture.timer, &TIM_TimeBaseStructure);
398 
399  TIM_SelectOnePulseMode(cfg->hsync_capture.timer, TIM_OPMode_Single);
400  TIM_SelectSlaveMode(cfg->hsync_capture.timer, TIM_SlaveMode_Trigger);
401 
402 
403 #ifdef PIOS_VIDEO_HSYNC_FALLING_EDGE
404  uint16_t tmpccer = cfg->hsync_capture.timer->CCER;
405 
406  /* Unfortunately not really a stdperiph function for this. */
407  if (cfg->hsync_capture.timer_chan == TIM_Channel_1) {
408  tmpccer &= (uint16_t)~(TIM_CCER_CC1NP);
409  tmpccer |= (uint16_t)(TIM_CCER_CC1P);
410  } else if (cfg->hsync_capture.timer_chan == TIM_Channel_2) {
411  tmpccer &= (uint16_t)~(TIM_CCER_CC2NP);
412  tmpccer |= (uint16_t)(TIM_CCER_CC2P);
413  }
414 
415  cfg->hsync_capture.timer->CCER = tmpccer;
416 #endif
417 
418 
419 #ifdef PIOS_VIDEO_INPUT_FILTER
420  uint16_t tmpccmr1 = cfg->hsync_capture.timer->CCMR1;
421 
422  if (cfg->hsync_capture.timer_chan == TIM_Channel_1) {
423  tmpccmr1 &= ((uint16_t)~TIM_CCMR1_IC1F);
424  tmpccmr1 |= 7 << 4;
425  /* 7 = Fdts/8, N=8. APB1=42MHz, so the prescaled clock input
426  * should be double that (84 MHz).
427  *
428  * 84MHz / 8 = 21Mhz... 8/21MHz = .38us
429  * require a steady value, different from the previous value
430  * for .38 microsecond before accepting a hsync clock
431  * trigger edge.
432  */
433  } else if (cfg->hsync_capture.timer_chan == TIM_Channel_2) {
434  tmpccmr1 &= ((uint16_t)~TIM_CCMR1_IC2F);
435  tmpccmr1 |= 9 << 12;
436  }
437 
438  cfg->hsync_capture.timer->CCMR1 = tmpccmr1;
439 #endif
440 
441  if (cfg->hsync_capture.timer_chan == TIM_Channel_1) {
442  TIM_SelectInputTrigger(cfg->hsync_capture.timer, TIM_TS_TI1FP1);
443  } else if (cfg->hsync_capture.timer_chan == TIM_Channel_2) {
444  TIM_SelectInputTrigger(cfg->hsync_capture.timer, TIM_TS_TI2FP2);
445  } else {
446  PIOS_Assert(0);
447  }
448 
449  TIM_SelectMasterSlaveMode(cfg->hsync_capture.timer, TIM_MasterSlaveMode_Enable);
450  TIM_SelectOutputTrigger(cfg->hsync_capture.timer, TIM_TRGOSource_Update);
451 
452  // Pixel timer: Outputs clock for SPI
453  GPIO_Init(cfg->pixel_timer.pin.gpio, (GPIO_InitTypeDef *)&(cfg->pixel_timer.pin.init));
454  if (cfg->pixel_timer.remap) {
455  GPIO_PinAFConfig(cfg->pixel_timer.pin.gpio, __builtin_ctz(cfg->pixel_timer.pin.init.GPIO_Pin), cfg->pixel_timer.remap);
456  }
457 
458  TIM_OC1Init(cfg->pixel_timer.timer, (TIM_OCInitTypeDef*)&cfg->tim_oc_init);
459  TIM_OC1PreloadConfig(cfg->pixel_timer.timer, TIM_OCPreload_Enable);
460  if (dev_cfg->pixel_timer.timer == TIM9) { // XXX or other fast timers
461  TIM_SetCompare1(cfg->pixel_timer.timer, pios_video_type_cfg_act->dc);
462  TIM_SetAutoreload(cfg->pixel_timer.timer, pios_video_type_cfg_act->period - 1);
463  } else {
464  TIM_SetCompare1(cfg->pixel_timer.timer, pios_video_type_cfg_act->dc / 2);
465  TIM_SetAutoreload(cfg->pixel_timer.timer, pios_video_type_cfg_act->period / 2 - 1);
466  }
467  TIM_ARRPreloadConfig(cfg->pixel_timer.timer, ENABLE);
468  TIM_CtrlPWMOutputs(cfg->pixel_timer.timer, ENABLE);
469 
470  if ((cfg->hsync_capture.timer == TIM2) && (cfg->pixel_timer.timer == TIM3)) {
471  TIM_SelectInputTrigger(cfg->pixel_timer.timer, TIM_TS_ITR1);
472  } else if ((cfg->hsync_capture.timer == TIM2) && (cfg->pixel_timer.timer == TIM9)) {
473  TIM_SelectInputTrigger(cfg->pixel_timer.timer, TIM_TS_ITR0);
474  } else {
475  PIOS_Assert(0);
476  }
477 
478  /* Enable the hsync cap global Interrupt */
479  NVIC_InitTypeDef NVIC_InitStructure;
480 
481  if (cfg->hsync_capture.timer == TIM2)
482  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
483  else
484  PIOS_Assert(0);
485 
486  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PIOS_IRQ_PRIO_HIGHEST;
487  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
488  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
489  NVIC_Init(&NVIC_InitStructure);
490 
491  /* Initialize the SPI block */
492  SPI_Init(cfg->level.regs, (SPI_InitTypeDef *)&(cfg->level.init));
493  SPI_Init(cfg->mask.regs, (SPI_InitTypeDef *)&(cfg->mask.init));
494 
495  /* Configure DMA for SPI*/
496  DMA_Init(cfg->mask.dma.tx.channel, (DMA_InitTypeDef *)&(cfg->mask.dma.tx.init));
497  DMA_Init(cfg->level.dma.tx.channel, (DMA_InitTypeDef *)&(cfg->level.dma.tx.init));
498 
499  /* Trigger interrupt when transfer complete */
500  DMA_ITConfig(cfg->level.dma.tx.channel, DMA_IT_TC, ENABLE);
501  DMA_ITConfig(cfg->mask.dma.tx.channel, DMA_IT_TC, ENABLE);
502 
503  /* Configure and clear buffers */
504  draw_buffer_level = buffer0_level;
505  draw_buffer_mask = buffer0_mask;
506  disp_buffer_level = buffer1_level;
507  disp_buffer_mask = buffer1_mask;
508  memset(disp_buffer_mask, 0, BUFFER_HEIGHT * BUFFER_WIDTH);
509  memset(disp_buffer_level, 0, BUFFER_HEIGHT * BUFFER_WIDTH);
512 
513  /* Configure DMA interrupt */
514  NVIC_Init((NVIC_InitTypeDef*)&cfg->level.dma.irq.init);
515  NVIC_Init((NVIC_InitTypeDef*)&cfg->mask.dma.irq.init);
516 
517  /* Enable SPI interrupts to DMA */
518  SPI_I2S_DMACmd(cfg->mask.regs, SPI_I2S_DMAReq_Tx, ENABLE);
519  SPI_I2S_DMACmd(cfg->level.regs, SPI_I2S_DMAReq_Tx, ENABLE);
520 
521  // Enable interrupts
522  PIOS_EXTI_Init(cfg->vsync);
523  TIM_ITConfig(cfg->hsync_capture.timer, TIM_IT_Update, ENABLE);
524 
525  // Enable the capture timer
526  TIM_Cmd(cfg->hsync_capture.timer, ENABLE);
527 }
528 
532 uint16_t PIOS_Video_GetLines(void)
533 {
534  return num_video_lines;
535 }
536 
541 {
542  return video_system_act;
543 }
544 
548 void PIOS_Video_SetLevels(uint8_t black, uint8_t white)
549 {
550  if (dev_cfg->set_bw_levels) {
551  dev_cfg->set_bw_levels(black, white);
552  }
553 }
554 
558 void PIOS_Video_SetXOffset(int8_t x_offset_in)
559 {
560  if (x_offset_in > 50)
561  x_offset_in = 50;
562  if (x_offset_in < -50)
563  x_offset_in = -50;
564 
565  x_offset_new = x_offset_in + PIOS_VIDEO_HSYNC_OFFSET;
566 }
567 
571 void PIOS_Video_SetYOffset(int8_t y_offset_in)
572 {
573  if (y_offset_in > 20)
574  y_offset_in = 20;
575  if (y_offset_in < -20)
576  y_offset_in = -20;
577  y_offset = y_offset_in;
578 }
579 
583 void PIOS_Video_SetXScale(uint8_t x_scale)
584 {
585  // Not supported by this driver
586  return;
587 }
588 
592 void PIOS_Video_Set3DConfig(enum pios_video_3d_mode mode, uint8_t right_eye_x_shift)
593 {
594  // Not supported by this driver
595  return;
596 }
597 #endif /* PIOS_INCLUDE_VIDEO */
pios_video_system
Definition: pios_video.h:50
const struct pios_video_type_boundary * pios_video_type_boundary_act
#define PIOS_VIDEO_HSYNC_OFFSET
Definition: pios_config.h:70
const struct pios_exti_cfg * vsync
Definition: pios_video.h:103
void PIOS_Video_SetXScale(uint8_t x_scale)
Main PiOS header to include all the compiled in PiOS options.
GPIO_InitTypeDef init
Definition: pios_stm32.h:61
uint8_t graphics_line_start
Definition: pios_video.h:89
OSD gen module, handles OSD draw. Parts from CL-OSD and SUPEROSD projects.
int32_t PIOS_EXTI_Init(const struct pios_exti_cfg *cfg)
uint16_t graphics_height_real
Definition: pios_video.h:87
GPIO_TypeDef * gpio
Definition: pios_stm32.h:60
enum pios_video_system PIOS_Video_GetSystem(void)
void(* set_bw_levels)(uint8_t, uint8_t)
Definition: pios_video.h:104
#define DMA2_Stream3_IRQHandler
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
pios_video_3d_mode
Definition: pios_video.h:45
#define PIOS_IRQ_PRIO_HIGHEST
Definition: pios_board.h:172
struct stm32_gpio pin
Definition: pios_tim_priv.h:17
#define BUFFER_HEIGHT
Definition: pios_video.h:148
struct pios_tim_channel pixel_timer
Definition: pios_video.h:101
const struct pios_spi_cfg level
Definition: pios_video.h:99
void PIOS_Video_SetYOffset(int8_t)
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
void PIOS_Video_Set3DConfig(enum pios_video_3d_mode mode, uint8_t right_eye_x_shift)
TIM_OCInitTypeDef tim_oc_init
Definition: pios_video.h:102
#define TIM2_IRQHandler
#define VIDEO_TYPE_PAL_ROWS
Definition: pios_video.h:137
uint8_t * draw_buffer_level
struct pios_semaphore * onScreenDisplaySemaphore
SPI_TypeDef * regs
Definition: pios_spi_priv.h:44
const struct pios_spi_cfg mask
Definition: pios_video.h:97
void PIOS_Video_SetXOffset(int8_t)
ws2811_dev_t pios_ws2811
Definition: pios_board.c:66
void PIOS_Video_Init(const struct pios_video_cfg *cfg)
struct pios_tim_channel hsync_capture
Definition: pios_video.h:100
enum channel_mode mode
Definition: pios_servo.c:58
uint8_t * draw_buffer_mask
uint16_t PIOS_Video_GetLines(void)
DMA_TypeDef * mask_dma
Definition: pios_video.h:96
struct stm32_gpio sclk
Definition: pios_spi_priv.h:47
void PIOS_Video_SetLevels(uint8_t, uint8_t)
DMA_TypeDef * level_dma
Definition: pios_video.h:98
#define DMA1_Stream4_IRQHandler
#define SWAP_BUFFS(tmp, a, b)
Definition: pios_video.h:152
void PIOS_WS2811_trigger_update(ws2811_dev_t dev)
Trigger an update of the LED strand.
Definition: pios_ws2811.c:197
uint32_t remap
Definition: pios_spi_priv.h:45
#define BUFFER_WIDTH
Definition: pios_video.h:147
bool PIOS_Vsync_ISR()
struct stm32_gpio miso
Definition: pios_spi_priv.h:48
TIM_TypeDef * timer
Definition: pios_tim_priv.h:14
SPI_InitTypeDef init
Definition: pios_spi_priv.h:46
uint16_t graphics_column_start
Definition: pios_video.h:88
#define PIOS_Assert(test)
Definition: pios_debug.h:52
uint8_t dma_buffer_length
Definition: pios_video.h:90