void max7456ReInit(void) { uint8_t srdata = 0; static bool firstInit = true; __spiBusTransactionBegin(busdev); switch (videoSignalCfg) { case VIDEO_SYSTEM_PAL: videoSignalReg = VIDEO_MODE_PAL | OSD_ENABLE; break; case VIDEO_SYSTEM_NTSC: videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; break; case VIDEO_SYSTEM_AUTO: srdata = max7456Send(MAX7456ADD_STAT, 0x00); if (VIN_IS_NTSC(srdata)) { videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; } else if (VIN_IS_PAL(srdata)) { videoSignalReg = VIDEO_MODE_PAL | OSD_ENABLE; } else { // No valid input signal, fallback to default (XXX NTSC for now) videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; } break; } if (videoSignalReg & VIDEO_MODE_PAL) { //PAL maxScreenSize = VIDEO_BUFFER_CHARS_PAL; } else { // NTSC maxScreenSize = VIDEO_BUFFER_CHARS_NTSC; } // Set all rows to same charactor black/white level max7456Brightness(0, 2); // Re-enable MAX7456 (last function call disables it) __spiBusTransactionBegin(busdev); // Make sure the Max7456 is enabled max7456Send(MAX7456ADD_VM0, videoSignalReg); max7456Send(MAX7456ADD_HOS, hosRegValue); max7456Send(MAX7456ADD_VOS, vosRegValue); max7456Send(MAX7456ADD_DMM, displayMemoryModeReg | CLEAR_DISPLAY); __spiBusTransactionEnd(busdev); // Clear shadow to force redraw all screen in non-dma mode. memset(shadowBuffer, 0, maxScreenSize); if (firstInit) { max7456DrawScreenSlow(); firstInit = false; } }
//because MAX7456 need some time to detect video system etc. we need to wait for a while to initialize it at startup //and in case of restart we need to reinitialize chip void max7456ReInit(void) { uint8_t maxScreenRows; uint8_t srdata = 0; uint16_t x; static bool firstInit = true; //do not init MAX before camera power up correctly if (millis() < 1500) return; ENABLE_MAX7456; switch(videoSignalCfg) { case PAL: videoSignalReg = VIDEO_MODE_PAL | OSD_ENABLE; break; case NTSC: videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; break; default: srdata = max7456Send(MAX7456ADD_STAT, 0x00); if ((0x02 & srdata) == 0x02) videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; } if (videoSignalReg & VIDEO_MODE_PAL) { //PAL maxScreenSize = VIDEO_BUFFER_CHARS_PAL; maxScreenRows = VIDEO_LINES_PAL; } else { // NTSC maxScreenSize = VIDEO_BUFFER_CHARS_NTSC; maxScreenRows = VIDEO_LINES_NTSC; } // set all rows to same charactor black/white level for(x = 0; x < maxScreenRows; x++) { max7456Send(MAX7456ADD_RB0 + x, BWBRIGHTNESS); } // make sure the Max7456 is enabled max7456Send(VM0_REG, videoSignalReg); max7456Send(DMM_REG, CLEAR_DISPLAY); DISABLE_MAX7456; //clear shadow to force redraw all screen in non-dma mode memset(shadowBuffer, 0, maxScreenSize); if (firstInit) { max7456RefreshAll(); firstInit = false; } }
void max7456ReInitIfRequired(void) { static uint32_t lastSigCheckMs = 0; static uint32_t videoDetectTimeMs = 0; static uint16_t reInitCount = 0; __spiBusTransactionBegin(busdev); const uint8_t stallCheck = max7456Send(MAX7456ADD_VM0|MAX7456ADD_READ, 0x00); __spiBusTransactionEnd(busdev); const timeMs_t nowMs = millis(); if (stallCheck != videoSignalReg) { max7456ReInit(); } else if ((videoSignalCfg == VIDEO_SYSTEM_AUTO) && ((nowMs - lastSigCheckMs) > MAX7456_SIGNAL_CHECK_INTERVAL_MS)) { // Adjust output format based on the current input format. __spiBusTransactionBegin(busdev); const uint8_t videoSense = max7456Send(MAX7456ADD_STAT, 0x00); __spiBusTransactionEnd(busdev); DEBUG_SET(DEBUG_MAX7456_SIGNAL, DEBUG_MAX7456_SIGNAL_MODEREG, videoSignalReg & VIDEO_MODE_MASK); DEBUG_SET(DEBUG_MAX7456_SIGNAL, DEBUG_MAX7456_SIGNAL_SENSE, videoSense & 0x7); DEBUG_SET(DEBUG_MAX7456_SIGNAL, DEBUG_MAX7456_SIGNAL_ROWS, max7456GetRowsCount()); if (videoSense & STAT_LOS) { videoDetectTimeMs = 0; } else { if ((VIN_IS_PAL(videoSense) && VIDEO_MODE_IS_NTSC(videoSignalReg)) || (VIN_IS_NTSC_alt(videoSense) && VIDEO_MODE_IS_PAL(videoSignalReg))) { if (videoDetectTimeMs) { if (millis() - videoDetectTimeMs > VIDEO_SIGNAL_DEBOUNCE_MS) { max7456ReInit(); DEBUG_SET(DEBUG_MAX7456_SIGNAL, DEBUG_MAX7456_SIGNAL_REINIT, ++reInitCount); } } else { // Wait for signal to stabilize videoDetectTimeMs = millis(); } } } lastSigCheckMs = nowMs; } //------------ end of (re)init------------------------------------- }
void max7456DrawScreen(void) { uint8_t check; static uint16_t pos = 0; int k = 0, buff_len=0; if (!max7456Lock && !fontIsLoading) { //-----------------detect MAX7456 fail, or initialize it at startup when it is ready-------- max7456Lock = true; ENABLE_MAX7456; check = max7456Send(VM0_REG | 0x80, 0x00); DISABLE_MAX7456; if ( check != videoSignalReg) max7456ReInit(); //------------ end of (re)init------------------------------------- for (k=0; k< MAX_CHARS2UPDATE; k++) { if (screenBuffer[pos] != shadowBuffer[pos]) { spiBuff[buff_len++] = MAX7456ADD_DMAH; spiBuff[buff_len++] = pos >> 8; spiBuff[buff_len++] = MAX7456ADD_DMAL; spiBuff[buff_len++] = pos & 0xff; spiBuff[buff_len++] = MAX7456ADD_DMDI; spiBuff[buff_len++] = screenBuffer[pos]; shadowBuffer[pos] = screenBuffer[pos]; k++; } if (++pos >= maxScreenSize) { pos = 0; break; } }
void max7456Init(const vcdProfile_t *pVcdProfile) { #ifdef MAX7456_SPI_CS_PIN max7456CsPin = IOGetByTag(IO_TAG(MAX7456_SPI_CS_PIN)); #endif IOInit(max7456CsPin, OWNER_OSD_CS, 0); IOConfigGPIO(max7456CsPin, SPI_IO_CS_CFG); spiSetDivisor(MAX7456_SPI_INSTANCE, SPI_CLOCK_STANDARD); // force soft reset on Max7456 ENABLE_MAX7456; max7456Send(MAX7456ADD_VM0, MAX7456_RESET); DISABLE_MAX7456; // Setup values to write to registers videoSignalCfg = pVcdProfile->video_system; hosRegValue = 32 - pVcdProfile->h_offset; vosRegValue = 16 - pVcdProfile->v_offset; #ifdef MAX7456_DMA_CHANNEL_TX dmaSetHandler(MAX7456_DMA_IRQ_HANDLER_ID, max7456_dma_irq_handler, NVIC_PRIO_MAX7456_DMA, 0); #endif // Real init will be made later when driver detect idle. }
/** * Sets the brighness of black and white pixels. * * @param black Black brightness (0-3, 0 is darkest) * @param white White brightness (0-3, 0 is darkest) */ void max7456Brightness(uint8_t black, uint8_t white) { const uint8_t reg = (black << 2) | (3 - white); __spiBusTransactionBegin(busdev); for (int i = MAX7456ADD_RB0; i <= MAX7456ADD_RB15; i++) { max7456Send(i, reg); } __spiBusTransactionEnd(busdev); }
/** * Sets the brighness of black and white pixels. * * @param black Black brightness (0-3, 0 is darkest) * @param white White brightness (0-3, 0 is darkest) */ void max7456Brightness(uint8_t black, uint8_t white) { const uint8_t reg = (black << 2) | (3 - white); ENABLE_MAX7456; for (int i = MAX7456ADD_RB0; i <= MAX7456ADD_RB15; i++) { max7456Send(i, reg); } DISABLE_MAX7456; }
/** * Sets inversion of black and white pixels. */ void max7456Invert(bool invert) { if (invert) { displayMemoryModeReg |= INVERT_PIXEL_COLOR; } else { displayMemoryModeReg &= ~INVERT_PIXEL_COLOR; } __spiBusTransactionBegin(busdev); max7456Send(MAX7456ADD_DMM, displayMemoryModeReg); __spiBusTransactionEnd(busdev); }
/** * Sets inversion of black and white pixels. */ void max7456Invert(bool invert) { if (invert) { displayMemoryModeReg |= INVERT_PIXEL_COLOR; } else { displayMemoryModeReg &= ~INVERT_PIXEL_COLOR; } ENABLE_MAX7456; max7456Send(MAX7456ADD_DMM, displayMemoryModeReg); DISABLE_MAX7456; }
//here we init only CS and try to init MAX for first time void max7456Init(uint8_t video_system) { #ifdef MAX7456_SPI_CS_PIN max7456CsPin = IOGetByTag(IO_TAG(MAX7456_SPI_CS_PIN)); #endif IOInit(max7456CsPin, OWNER_OSD, RESOURCE_SPI_CS, 0); IOConfigGPIO(max7456CsPin, SPI_IO_CS_CFG); spiSetDivisor(MAX7456_SPI_INSTANCE, SPI_CLOCK_STANDARD); // force soft reset on Max7456 ENABLE_MAX7456; max7456Send(VM0_REG, MAX7456_RESET); DISABLE_MAX7456; videoSignalCfg = video_system; #ifdef MAX7456_DMA_CHANNEL_TX dmaSetHandler(MAX7456_DMA_IRQ_HANDLER_ID, max7456_dma_irq_handler, NVIC_PRIO_MAX7456_DMA, 0); #endif //real init will be made letter when driver idle detect }
void max7456Init(const max7456Config_t *max7456Config, const vcdProfile_t *pVcdProfile, bool cpuOverclock) { max7456HardwareReset(); if (!max7456Config->csTag) { return; } busdev->busdev_u.spi.csnPin = IOGetByTag(max7456Config->csTag); if (!IOIsFreeOrPreinit(busdev->busdev_u.spi.csnPin)) { return; } IOInit(busdev->busdev_u.spi.csnPin, OWNER_OSD_CS, 0); IOConfigGPIO(busdev->busdev_u.spi.csnPin, SPI_IO_CS_CFG); IOHi(busdev->busdev_u.spi.csnPin); spiBusSetInstance(busdev, spiInstanceByDevice(SPI_CFG_TO_DEV(max7456Config->spiDevice))); // Detect device type by writing and reading CA[8] bit at CMAL[6]. // Do this at half the speed for safety. spiSetDivisor(busdev->busdev_u.spi.instance, MAX7456_SPI_CLK * 2); max7456Send(MAX7456ADD_CMAL, (1 << 6)); // CA[8] bit if (max7456Send(MAX7456ADD_CMAL|MAX7456ADD_READ, 0xff) & (1 << 6)) { max7456DeviceType = MAX7456_DEVICE_TYPE_AT; } else { max7456DeviceType = MAX7456_DEVICE_TYPE_MAX; } #if defined(USE_OVERCLOCK) // Determine SPI clock divisor based on config and the device type. switch (max7456Config->clockConfig) { case MAX7456_CLOCK_CONFIG_HALF: max7456SpiClock = MAX7456_SPI_CLK * 2; break; case MAX7456_CLOCK_CONFIG_OC: max7456SpiClock = (cpuOverclock && (max7456DeviceType == MAX7456_DEVICE_TYPE_MAX)) ? MAX7456_SPI_CLK * 2 : MAX7456_SPI_CLK; break; case MAX7456_CLOCK_CONFIG_FULL: max7456SpiClock = MAX7456_SPI_CLK; break; } DEBUG_SET(DEBUG_MAX7456_SPICLOCK, DEBUG_MAX7456_SPICLOCK_OVERCLOCK, cpuOverclock); DEBUG_SET(DEBUG_MAX7456_SPICLOCK, DEBUG_MAX7456_SPICLOCK_DEVTYPE, max7456DeviceType); DEBUG_SET(DEBUG_MAX7456_SPICLOCK, DEBUG_MAX7456_SPICLOCK_DIVISOR, max7456SpiClock); #else UNUSED(max7456Config); UNUSED(cpuOverclock); #endif spiSetDivisor(busdev->busdev_u.spi.instance, max7456SpiClock); // force soft reset on Max7456 __spiBusTransactionBegin(busdev); max7456Send(MAX7456ADD_VM0, MAX7456_RESET); __spiBusTransactionEnd(busdev); // Setup values to write to registers videoSignalCfg = pVcdProfile->video_system; hosRegValue = 32 - pVcdProfile->h_offset; vosRegValue = 16 - pVcdProfile->v_offset; #ifdef MAX7456_DMA_CHANNEL_TX dmaSetHandler(MAX7456_DMA_IRQ_HANDLER_ID, max7456_dma_irq_handler, NVIC_PRIO_MAX7456_DMA, 0); #endif // Real init will be made later when driver detect idle. }
void max7456DrawScreen(void) { uint8_t stallCheck; uint8_t videoSense; static uint32_t lastSigCheckMs = 0; uint32_t nowMs; static uint32_t videoDetectTimeMs = 0; static uint16_t pos = 0; int k = 0, buff_len=0; if (!max7456Lock && !fontIsLoading) { // (Re)Initialize MAX7456 at startup or stall is detected. max7456Lock = true; ENABLE_MAX7456; stallCheck = max7456Send(MAX7456ADD_VM0|MAX7456ADD_READ, 0x00); DISABLE_MAX7456; nowMs = millis(); if (stallCheck != videoSignalReg) { max7456ReInit(); } else if ((videoSignalCfg == VIDEO_SYSTEM_AUTO) && ((nowMs - lastSigCheckMs) > MAX7456_SIGNAL_CHECK_INTERVAL_MS)) { // Adjust output format based on the current input format. ENABLE_MAX7456; videoSense = max7456Send(MAX7456ADD_STAT, 0x00); DISABLE_MAX7456; #ifdef DEBUG_MAX7456_SIGNAL debug[0] = videoSignalReg & VIDEO_MODE_MASK; debug[1] = videoSense & 0x7; debug[3] = max7456GetRowsCount(); #endif if (videoSense & STAT_LOS) { videoDetectTimeMs = 0; } else { if ((VIN_IS_PAL(videoSense) && VIDEO_MODE_IS_NTSC(videoSignalReg)) || (VIN_IS_NTSC_alt(videoSense) && VIDEO_MODE_IS_PAL(videoSignalReg))) { if (videoDetectTimeMs) { if (millis() - videoDetectTimeMs > VIDEO_SIGNAL_DEBOUNCE_MS) { max7456ReInit(); #ifdef DEBUG_MAX7456_SIGNAL debug[2]++; #endif } } else { // Wait for signal to stabilize videoDetectTimeMs = millis(); } } } lastSigCheckMs = nowMs; } //------------ end of (re)init------------------------------------- for (k=0; k< MAX_CHARS2UPDATE; k++) { if (screenBuffer[pos] != shadowBuffer[pos]) { spiBuff[buff_len++] = MAX7456ADD_DMAH; spiBuff[buff_len++] = pos >> 8; spiBuff[buff_len++] = MAX7456ADD_DMAL; spiBuff[buff_len++] = pos & 0xff; spiBuff[buff_len++] = MAX7456ADD_DMDI; spiBuff[buff_len++] = screenBuffer[pos]; shadowBuffer[pos] = screenBuffer[pos]; k++; } if (++pos >= maxScreenSize) { pos = 0; break; } }
void max7456ReInit(void) { uint8_t maxScreenRows; uint8_t srdata = 0; uint16_t x; static bool firstInit = true; ENABLE_MAX7456; switch(videoSignalCfg) { case VIDEO_SYSTEM_PAL: videoSignalReg = VIDEO_MODE_PAL | OSD_ENABLE; break; case VIDEO_SYSTEM_NTSC: videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; break; case VIDEO_SYSTEM_AUTO: srdata = max7456Send(MAX7456ADD_STAT, 0x00); if (VIN_IS_NTSC(srdata)) { videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; } else if (VIN_IS_PAL(srdata)) { videoSignalReg = VIDEO_MODE_PAL | OSD_ENABLE; } else { // No valid input signal, fallback to default (XXX NTSC for now) videoSignalReg = VIDEO_MODE_NTSC | OSD_ENABLE; } break; } if (videoSignalReg & VIDEO_MODE_PAL) { //PAL maxScreenSize = VIDEO_BUFFER_CHARS_PAL; maxScreenRows = VIDEO_LINES_PAL; } else { // NTSC maxScreenSize = VIDEO_BUFFER_CHARS_NTSC; maxScreenRows = VIDEO_LINES_NTSC; } // Set all rows to same charactor black/white level. for(x = 0; x < maxScreenRows; x++) { max7456Send(MAX7456ADD_RB0 + x, BWBRIGHTNESS); } // Make sure the Max7456 is enabled max7456Send(MAX7456ADD_VM0, videoSignalReg); max7456Send(MAX7456ADD_HOS, hosRegValue); max7456Send(MAX7456ADD_VOS, vosRegValue); max7456Send(MAX7456ADD_DMM, CLEAR_DISPLAY); DISABLE_MAX7456; // Clear shadow to force redraw all screen in non-dma mode. memset(shadowBuffer, 0, maxScreenSize); if (firstInit) { max7456RefreshAll(); firstInit = false; } }