dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_video_quadspi.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_QUADSPI)
34 
35 #if !defined(PIOS_VIDEO_QUADSPI_Y_OFFSET)
36 #define PIOS_VIDEO_QUADSPI_Y_OFFSET 0
37 #endif /* !defined(PIOS_VIDEO_QUADSPI_Y_OFFSET) */
38 
39 #if defined(PIOS_INCLUDE_FREERTOS)
40 #include "FreeRTOS.h"
41 #endif /* defined(PIOS_INCLUDE_FREERTOS) */
42 
43 #include "pios.h"
44 #include "pios_video.h"
45 #include "pios_semaphore.h"
46 
47 // How many frames until we redraw
48 #define VSYNC_REDRAW_CNT 2
49 
51 
52 #define GRPAHICS_RIGHT_NTSC 351
53 #define GRPAHICS_RIGHT_PAL 359
54 
55 static const struct pios_video_type_boundary pios_video_type_boundary_ntsc = {
56  .graphics_right = GRPAHICS_RIGHT_NTSC, // must be: graphics_width_real - 1
57  .graphics_bottom = 239, // must be: graphics_height_real - 1
58 };
59 
60 static const struct pios_video_type_boundary pios_video_type_boundary_pal = {
61  .graphics_right = GRPAHICS_RIGHT_PAL, // must be: graphics_width_real - 1
62  .graphics_bottom = 265, // must be: graphics_height_real - 1
63 };
64 
65 #define NTSC_BYTES (GRPAHICS_RIGHT_NTSC / (8 / PIOS_VIDEO_BITS_PER_PIXEL) + 1)
66 #define PAL_BYTES (GRPAHICS_RIGHT_PAL / (8 / PIOS_VIDEO_BITS_PER_PIXEL) + 1)
67 
68 static const struct pios_video_type_cfg pios_video_type_cfg_ntsc = {
69  .graphics_height_real = 240, // Real visible lines
70  .graphics_column_start = 260, // First visible OSD column (after Hsync)
71  .graphics_line_start = 16, // First visible OSD line
72  .dma_buffer_length = NTSC_BYTES + NTSC_BYTES % 4, // DMA buffer length in bytes (has to be multiple of 4)
73 };
74 
75 static const struct pios_video_type_cfg pios_video_type_cfg_pal = {
76  .graphics_height_real = 266, // Real visible lines
77  .graphics_column_start = 420, // First visible OSD column (after Hsync)
78  .graphics_line_start = 28, // First visible OSD line
79  .dma_buffer_length = PAL_BYTES + PAL_BYTES % 4, // DMA buffer length in bytes (has to be multiple of 4)
80 };
81 
82 // Allocate buffers.
83 // Must be allocated in one block, so it is in a struct.
84 struct _buffers {
85  uint8_t buffer0[BUFFER_HEIGHT * BUFFER_WIDTH];
86  uint8_t buffer1[BUFFER_HEIGHT * BUFFER_WIDTH];
87 } buffers;
88 
89 // Remove the struct definition (makes it easier to write for).
90 #define buffer0 (buffers.buffer0)
91 #define buffer1 (buffers.buffer1)
92 
93 // Pointers to each of these buffers.
94 uint8_t *draw_buffer;
95 uint8_t *disp_buffer;
96 
97 
98 const struct pios_video_type_boundary *pios_video_type_boundary_act = &pios_video_type_boundary_pal;
99 
100 // Private variables
101 static int16_t active_line = 0;
102 static uint32_t buffer_offset;
103 static int8_t y_offset = 0;
104 static const struct pios_video_cfg *dev_cfg = NULL;
105 static uint16_t num_video_lines = 0;
106 static enum pios_video_system video_system_act = PIOS_VIDEO_SYSTEM_NONE;
107 static enum pios_video_system video_system_tmp = PIOS_VIDEO_SYSTEM_PAL;
108 static const struct pios_video_type_cfg *pios_video_type_cfg_act = &pios_video_type_cfg_pal;
109 
110 // Private functions
111 static void swap_buffers();
112 
116 bool PIOS_Vsync_ISR()
117 {
118  static bool woken = false;
119  static uint16_t Vsync_update = 0;
120 
121  // discard spurious vsync pulses (due to improper grounding), so we don't overload the CPU
122  if (active_line < pios_video_type_cfg_ntsc.graphics_height_real - 10) {
123  return false;
124  }
125 
126  // Update the number of video lines
127  num_video_lines = active_line + pios_video_type_cfg_act->graphics_line_start + y_offset;
128 
129  // check video type
130  if (num_video_lines > VIDEO_TYPE_PAL_ROWS) {
131  video_system_tmp = PIOS_VIDEO_SYSTEM_PAL;
132  }
133 
134  // if video type has changed set new active values
135  if (video_system_act != video_system_tmp) {
136  video_system_act = video_system_tmp;
137  if (video_system_act == PIOS_VIDEO_SYSTEM_NTSC) {
138  pios_video_type_boundary_act = &pios_video_type_boundary_ntsc;
139  pios_video_type_cfg_act = &pios_video_type_cfg_ntsc;
140  } else {
141  pios_video_type_boundary_act = &pios_video_type_boundary_pal;
142  pios_video_type_cfg_act = &pios_video_type_cfg_pal;
143  }
144  }
145 
146  video_system_tmp = PIOS_VIDEO_SYSTEM_NTSC;
147 
148  // Every VSYNC_REDRAW_CNT field: swap buffers and trigger redraw
149  if (++Vsync_update >= VSYNC_REDRAW_CNT) {
150  Vsync_update = 0;
151  swap_buffers();
152  PIOS_Semaphore_Give_FromISR(onScreenDisplaySemaphore, &woken);
153  }
154 
155  // Get ready for the first line. We will start outputting data at line zero.
156  active_line = 0 - (pios_video_type_cfg_act->graphics_line_start + y_offset);
157  buffer_offset = 0;
158 
159 #if defined(PIOS_INCLUDE_FREERTOS)
160  /* Yield From ISR if needed */
161  portEND_SWITCHING_ISR(woken == true ? pdTRUE : pdFALSE);
162 #endif
163  return woken;
164 }
165 
166 bool PIOS_Hsync_ISR()
167 {
168  static bool woken = false;
169 
170  active_line++;
171 
172  if ((active_line >= 0) && (active_line < pios_video_type_cfg_act->graphics_height_real)) {
173  // Check if QUADSPI is busy
174  if (QUADSPI->SR & 0x20)
175  goto exit;
176 
177  // Disable DMA
178  dev_cfg->dma.tx.channel->CR &= ~(uint32_t)DMA_SxCR_EN;
179 
180  // Clear the DMA interrupt flags
181  dev_cfg->pixel_dma->HIFCR |= DMA_FLAG_TCIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_FEIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_DMEIF7;
182 
183  // Load new line
184  dev_cfg->dma.tx.channel->M0AR = (uint32_t)&disp_buffer[buffer_offset];
185 
186  // Set length
187  dev_cfg->dma.tx.channel->NDTR = (uint16_t)pios_video_type_cfg_act->dma_buffer_length;
188  QUADSPI->DLR = (uint32_t)pios_video_type_cfg_act->dma_buffer_length - 1;
189 
190  // Enable DMA
191  dev_cfg->dma.tx.channel->CR |= (uint32_t)DMA_SxCR_EN;
192 
193  buffer_offset += BUFFER_WIDTH;
194  }
195 
196 exit:
197 #if defined(PIOS_INCLUDE_FREERTOS)
198  /* Yield From ISR if needed */
199  portEND_SWITCHING_ISR(woken == true ? pdTRUE : pdFALSE);
200 #endif
201  return woken;
202 }
203 
209 static void swap_buffers()
210 {
211  // While we could use XOR swap this is more reliable and
212  // dependable and it's only called a few times per second.
213  // Many compilers should optimize these to EXCH instructions.
214  uint8_t *tmp;
215 
217 }
218 
222 void PIOS_Video_Init(const struct pios_video_cfg *cfg)
223 {
224  dev_cfg = cfg; // store config before enabling interrupt
225 
226  /* Enable QUADSPI clock */
227  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_QSPI, ENABLE);
228 
229  /* Map pins to QUADSPI */
230  GPIO_PinAFConfig(cfg->sclk.gpio, __builtin_ctz(cfg->sclk.init.GPIO_Pin), GPIO_AF9_QUADSPI);
231  GPIO_PinAFConfig(cfg->bk1_io0.gpio, __builtin_ctz(cfg->bk1_io0.init.GPIO_Pin), GPIO_AF9_QUADSPI);
232  GPIO_PinAFConfig(cfg->bk1_io1.gpio, __builtin_ctz(cfg->bk1_io1.init.GPIO_Pin), GPIO_AF9_QUADSPI);
233 
234  GPIO_Init(cfg->sclk.gpio, (GPIO_InitTypeDef *)&(cfg->sclk.init));
235  GPIO_Init(cfg->bk1_io0.gpio, (GPIO_InitTypeDef *)&(cfg->bk1_io0.init));
236  GPIO_Init(cfg->bk1_io1.gpio, (GPIO_InitTypeDef *)&(cfg->bk1_io1.init));
237 
238  /* Configure QUADSPI */
239  QSPI_Init(&cfg->qspi_init);
240 
241  QSPI_ComConfig_InitTypeDef qspi_com_config;
242  QSPI_ComConfig_StructInit(&qspi_com_config);
243 
244  qspi_com_config.QSPI_ComConfig_FMode = QSPI_ComConfig_FMode_Indirect_Write;
245  qspi_com_config.QSPI_ComConfig_DDRMode = QSPI_ComConfig_DDRMode_Disable;
246  qspi_com_config.QSPI_ComConfig_DHHC = QSPI_ComConfig_DHHC_Disable;
247  qspi_com_config.QSPI_ComConfig_SIOOMode = QSPI_ComConfig_SIOOMode_Disable;
248  qspi_com_config.QSPI_ComConfig_DMode = QSPI_ComConfig_DMode_2Line;
249  qspi_com_config.QSPI_ComConfig_DummyCycles = 0;
250  qspi_com_config.QSPI_ComConfig_ABMode = QSPI_ComConfig_ABMode_NoAlternateByte;
251  qspi_com_config.QSPI_ComConfig_ADMode = QSPI_ComConfig_ADMode_NoAddress;
252  qspi_com_config.QSPI_ComConfig_IMode = QSPI_ComConfig_IMode_NoInstruction;
253  QSPI_ComConfig_Init(&qspi_com_config);
254 
255  QSPI_SetFIFOThreshold(3);
256 
257  /* Configure DMA */
258  DMA_Init(cfg->dma.tx.channel, (DMA_InitTypeDef *)&(cfg->dma.tx.init));
259 
260  /* Configure and clear buffers */
261  draw_buffer = buffer0;
262  disp_buffer = buffer1;
263 
264  /* Enable TC interrupt */
265  QSPI_ITConfig(QSPI_IT_TC, ENABLE);
266  QSPI_ITConfig(QSPI_IT_FT, ENABLE);
267 
268  /* Enable DMA */
269  QSPI_DMACmd(ENABLE);
270 
271  // Enable the QUADSPI
272  QSPI_Cmd(ENABLE);
273 
274  // Enable interrupts
275  PIOS_EXTI_Init(cfg->vsync);
276  PIOS_EXTI_Init(cfg->hsync);
277 }
278 
282 uint16_t PIOS_Video_GetLines(void)
283 {
284  return num_video_lines;
285 }
286 
291 {
292  return video_system_act;
293 }
294 
298 void PIOS_Video_SetLevels(uint8_t black, uint8_t white)
299 {
300  if (dev_cfg->set_bw_levels) {
301  dev_cfg->set_bw_levels(black, white);
302  }
303 }
304 
308 void PIOS_Video_SetXOffset(int8_t x_offset_in)
309 {
310  if (x_offset_in > 20)
311  x_offset_in = 20;
312  if (x_offset_in < -20)
313  x_offset_in = -20;
314 
315  if (dev_cfg->set_x_offset) {
316  dev_cfg->set_x_offset(x_offset_in);
317  }
318 }
319 
323 void PIOS_Video_SetYOffset(int8_t y_offset_in)
324 {
325  if (y_offset_in > 20)
326  y_offset_in = 20;
327  if (y_offset_in < -20)
328  y_offset_in = -20;
329  y_offset = y_offset_in + PIOS_VIDEO_QUADSPI_Y_OFFSET;
330 }
331 
335 void PIOS_Video_SetXScale(uint8_t x_scale)
336 {
337  if (dev_cfg->set_x_scale) {
338  dev_cfg->set_x_scale(x_scale);
339  }
340 }
341 
345 void PIOS_Video_Set3DConfig(enum pios_video_3d_mode mode, uint8_t right_eye_x_shift)
346 {
347  if (dev_cfg->set_3d_config){
348  dev_cfg->set_3d_config(mode, right_eye_x_shift);
349  }
350 }
351 #endif /* PIOS_INCLUDE_VIDEO_SINGLESPI */
pios_video_system
Definition: pios_video.h:50
const struct pios_video_type_boundary * pios_video_type_boundary_act
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.
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)
void(* set_3d_config)(enum pios_video_3d_mode, uint8_t)
Definition: pios_video.h:106
uint16_t graphics_height_real
Definition: pios_video.h:87
enum pios_video_system PIOS_Video_GetSystem(void)
void(* set_bw_levels)(uint8_t, uint8_t)
Definition: pios_video.h:104
bool PIOS_Semaphore_Give_FromISR(struct pios_semaphore *sema, bool *woken)
pios_video_3d_mode
Definition: pios_video.h:45
#define BUFFER_HEIGHT
Definition: pios_video.h:148
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)
#define VIDEO_TYPE_PAL_ROWS
Definition: pios_video.h:137
struct pios_semaphore * onScreenDisplaySemaphore
void PIOS_Video_SetXOffset(int8_t)
void PIOS_Video_Init(const struct pios_video_cfg *cfg)
uint8_t * disp_buffer
void(* set_x_scale)(uint8_t)
Definition: pios_video.h:105
bool PIOS_Hsync_ISR()
enum channel_mode mode
Definition: pios_servo.c:58
uint8_t * draw_buffer
uint16_t PIOS_Video_GetLines(void)
void PIOS_Video_SetLevels(uint8_t, uint8_t)
#define SWAP_BUFFS(tmp, a, b)
Definition: pios_video.h:152
#define BUFFER_WIDTH
Definition: pios_video.h:147
bool PIOS_Vsync_ISR()
#define PIOS_VIDEO_QUADSPI_Y_OFFSET
Definition: pios_config.h:79
uint8_t dma_buffer_length
Definition: pios_video.h:90