939 lines
31 KiB
C
939 lines
31 KiB
C
//*****************************************************************************
|
|
//
|
|
//! @file HM01B0.c
|
|
//!
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include "am_mcu_apollo.h"
|
|
#include "am_bsp.h"
|
|
#include "am_util.h"
|
|
#include "HM01B0.h"
|
|
#include "HM01B0_Walking1s_01.h"
|
|
#include "platform.h"
|
|
|
|
#define read_vsync() (AM_REGVAL(AM_REGADDR(GPIO, RDA)) & (1 << HM01B0_PIN_VSYNC))
|
|
#define read_hsync() (AM_REGVAL(AM_REGADDR(GPIO, RDA)) & (1 << HM01B0_PIN_HSYNC))
|
|
#define read_pclk() (AM_REGVAL(AM_REGADDR(GPIO, RDA)) & (1 << HM01B0_PIN_PCLK))
|
|
#define read_byte() (APBDMA->BBINPUT)
|
|
|
|
const am_hal_gpio_pincfg_t g_HM01B0_pin_int =
|
|
{
|
|
.uFuncSel = 3,
|
|
.eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE,
|
|
.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI,
|
|
.eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE,
|
|
.eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN
|
|
};
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Write HM01B0 registers
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param ui16Reg - Register address.
|
|
//! @param pui8Value - Pointer to the data to be written.
|
|
//! @param ui32NumBytes - Length of the data in bytes to be written.
|
|
//!
|
|
//! This function writes value to HM01B0 registers.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_write_reg(hm01b0_cfg_t *psCfg, \
|
|
uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes)
|
|
{
|
|
am_hal_iom_transfer_t Transaction;
|
|
|
|
//
|
|
// Create the transaction.
|
|
//
|
|
Transaction.ui32InstrLen = sizeof(uint16_t);
|
|
Transaction.ui32Instr = (ui16Reg & 0x0000FFFF);
|
|
Transaction.eDirection = AM_HAL_IOM_TX;
|
|
Transaction.ui32NumBytes = ui32NumBytes;
|
|
Transaction.pui32TxBuffer = (uint32_t *) pui8Value;
|
|
Transaction.uPeerInfo.ui32I2CDevAddr = (uint32_t) psCfg->ui16SlvAddr;
|
|
Transaction.bContinue = false;
|
|
Transaction.ui8RepeatCount = 0;
|
|
Transaction.ui32PauseCondition = 0;
|
|
Transaction.ui32StatusSetClr = 0;
|
|
|
|
//
|
|
// Execute the transction over IOM.
|
|
//
|
|
if (am_hal_iom_blocking_transfer(psCfg->pIOMHandle, &Transaction))
|
|
{
|
|
return HM01B0_ERR_I2C;
|
|
}
|
|
|
|
return HM01B0_ERR_OK;
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Read HM01B0 registers
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param ui16Reg - Register address.
|
|
//! @param pui8Value - Pointer to the buffer for read data to be put into.
|
|
//! @param ui32NumBytes - Length of the data to be read.
|
|
//!
|
|
//! This function reads value from HM01B0 registers.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_read_reg(hm01b0_cfg_t *psCfg, \
|
|
uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes)
|
|
{
|
|
am_hal_iom_transfer_t Transaction;
|
|
|
|
//
|
|
// Create the transaction.
|
|
//
|
|
Transaction.ui32InstrLen = sizeof(uint16_t);
|
|
Transaction.ui32Instr = (ui16Reg & 0x0000FFFF);
|
|
Transaction.eDirection = AM_HAL_IOM_RX;
|
|
Transaction.ui32NumBytes = ui32NumBytes;
|
|
Transaction.pui32RxBuffer = (uint32_t *) pui8Value;;
|
|
Transaction.uPeerInfo.ui32I2CDevAddr = (uint32_t) psCfg->ui16SlvAddr;
|
|
Transaction.bContinue = false;
|
|
Transaction.ui8RepeatCount = 0;
|
|
Transaction.ui32PauseCondition = 0;
|
|
Transaction.ui32StatusSetClr = 0;
|
|
|
|
//
|
|
// Execute the transction over IOM.
|
|
//
|
|
if (am_hal_iom_blocking_transfer(psCfg->pIOMHandle, &Transaction))
|
|
{
|
|
return HM01B0_ERR_I2C;
|
|
}
|
|
|
|
return HM01B0_ERR_OK;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Load HM01B0 a given script
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param psScrip - Pointer to the script to be loaded.
|
|
//! @param ui32ScriptCmdNum - Number of entries in a given script.
|
|
//!
|
|
//! This function loads HM01B0 a given script.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_load_script(hm01b0_cfg_t *psCfg, hm_script_t *psScript, uint32_t ui32ScriptCmdNum)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
for (uint32_t idx = 0; idx < ui32ScriptCmdNum; idx++)
|
|
{
|
|
ui32Err = hm01b0_write_reg(psCfg, \
|
|
(psScript + idx)->ui16Reg, \
|
|
&((psScript + idx)->ui8Val), \
|
|
sizeof(uint8_t));
|
|
if (ui32Err != HM01B0_ERR_OK)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Power up HM01B0
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function powers up HM01B0.
|
|
//!
|
|
//! @return none.
|
|
//
|
|
//*****************************************************************************
|
|
void hm01b0_power_up(hm01b0_cfg_t *psCfg)
|
|
{
|
|
// place holder
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Power down HM01B0
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function powers up HM01B0.
|
|
//!
|
|
//! @return none.
|
|
//
|
|
//*****************************************************************************
|
|
void hm01b0_power_down(hm01b0_cfg_t *psCfg)
|
|
{
|
|
// place holder
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Enable MCLK
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function utilizes CTimer to generate MCLK for HM01B0.
|
|
//!
|
|
//! @return none.
|
|
//
|
|
//*****************************************************************************
|
|
void hm01b0_mclk_enable(hm01b0_cfg_t *psCfg)
|
|
{
|
|
#define MCLK_UI64PATTERN 0x55555555
|
|
#define MCLK_UI64PATTERNLEN 31
|
|
|
|
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
|
|
|
|
//
|
|
// Set up timer.
|
|
//
|
|
am_hal_ctimer_clear(psCfg->ui32CTimerModule, psCfg->ui32CTimerSegment);
|
|
|
|
am_hal_ctimer_config_single(psCfg->ui32CTimerModule,
|
|
psCfg->ui32CTimerSegment,
|
|
(
|
|
AM_HAL_CTIMER_FN_PTN_REPEAT |
|
|
AM_HAL_CTIMER_HFRC_12MHZ
|
|
)
|
|
);
|
|
|
|
//
|
|
// Set the pattern in the CMPR registers.
|
|
//
|
|
am_hal_ctimer_compare_set(psCfg->ui32CTimerModule, psCfg->ui32CTimerSegment, 0,
|
|
(uint32_t)(MCLK_UI64PATTERN & 0xFFFF));
|
|
am_hal_ctimer_compare_set(psCfg->ui32CTimerModule, psCfg->ui32CTimerSegment, 1,
|
|
(uint32_t)((MCLK_UI64PATTERN >> 16) & 0xFFFF));
|
|
|
|
//
|
|
// Set the timer trigger and pattern length.
|
|
//
|
|
am_hal_ctimer_config_trigger(psCfg->ui32CTimerModule,
|
|
psCfg->ui32CTimerSegment,
|
|
(
|
|
(MCLK_UI64PATTERNLEN << CTIMER_AUX0_TMRA0LMT_Pos) |
|
|
(CTIMER_AUX0_TMRB0TRIG_DIS << CTIMER_AUX0_TMRA0TRIG_Pos)
|
|
)
|
|
);
|
|
|
|
//
|
|
// Configure timer output pin.
|
|
//
|
|
am_hal_ctimer_output_config(psCfg->ui32CTimerModule,
|
|
psCfg->ui32CTimerSegment,
|
|
psCfg->ui32CTimerOutputPin,
|
|
AM_HAL_CTIMER_OUTPUT_NORMAL,
|
|
AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA);
|
|
|
|
//
|
|
// Start the timer.
|
|
//
|
|
am_hal_ctimer_start(psCfg->ui32CTimerModule, psCfg->ui32CTimerSegment);
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Disable MCLK
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function disable CTimer to stop MCLK for HM01B0.
|
|
//!
|
|
//! @return none.
|
|
//
|
|
//*****************************************************************************
|
|
void hm01b0_mclk_disable(hm01b0_cfg_t *psCfg)
|
|
{
|
|
//
|
|
// Stop the timer.
|
|
//
|
|
am_hal_ctimer_stop(psCfg->ui32CTimerModule, psCfg->ui32CTimerSegment);
|
|
am_hal_gpio_pinconfig(psCfg->ui32CTimerOutputPin, g_AM_HAL_GPIO_DISABLE);
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Initialize interfaces
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function initializes interfaces.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_init_if(hm01b0_cfg_t *psCfg)
|
|
{
|
|
void *pIOMHandle = NULL;
|
|
|
|
if ( psCfg->ui32IOMModule > AM_REG_IOM_NUM_MODULES )
|
|
{
|
|
return HM01B0_ERR_I2C;
|
|
}
|
|
|
|
//
|
|
// Enable fault detection.
|
|
//
|
|
#if AM_APOLLO3_MCUCTRL
|
|
am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_FAULT_CAPTURE_ENABLE, 0);
|
|
#else // AM_APOLLO3_MCUCTRL
|
|
am_hal_mcuctrl_fault_capture_enable();
|
|
#endif // AM_APOLLO3_MCUCTRL
|
|
|
|
//
|
|
// Initialize the IOM instance.
|
|
// Enable power to the IOM instance.
|
|
// Configure the IOM for Serial operation during initialization.
|
|
// Enable the IOM.
|
|
//
|
|
if (am_hal_iom_initialize(psCfg->ui32IOMModule, &pIOMHandle) ||
|
|
am_hal_iom_power_ctrl(pIOMHandle, AM_HAL_SYSCTRL_WAKE, false) ||
|
|
am_hal_iom_configure(pIOMHandle, &(psCfg->sIOMCfg)) ||
|
|
am_hal_iom_enable(pIOMHandle))
|
|
{
|
|
return HM01B0_ERR_I2C;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Configure the IOM pins.
|
|
//
|
|
am_bsp_iom_pins_enable(psCfg->ui32IOMModule, psCfg->eIOMMode);
|
|
|
|
psCfg->pIOMHandle = pIOMHandle;
|
|
}
|
|
|
|
// initialize pins for camera parallel interface.
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD0);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD1);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD2);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD3);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD4);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD5);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD6);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD7);
|
|
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD0);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD1);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD2);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD3);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD4);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD5);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD6);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD7);
|
|
|
|
am_hal_gpio_fast_pinconfig((uint64_t)0x1 << psCfg->ui8PinD0 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD1 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD2 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD3 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD4 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD5 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD6 |
|
|
(uint64_t)0x1 << psCfg->ui8PinD7,
|
|
g_AM_HAL_GPIO_INPUT, 0);
|
|
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinVSYNC, g_AM_HAL_GPIO_INPUT);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinHSYNC, g_AM_HAL_GPIO_INPUT);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinPCLK, g_AM_HAL_GPIO_INPUT);
|
|
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinTrig, g_AM_HAL_GPIO_OUTPUT);
|
|
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinInt, g_AM_HAL_GPIO_DISABLE);
|
|
// am_hal_gpio_pinconfig(psCfg->ui8PinInt, g_HM01B0_pin_int);
|
|
// am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(psCfg->ui8PinInt));
|
|
// am_hal_gpio_interrupt_enable(AM_HAL_GPIO_BIT(psCfg->ui8PinInt));
|
|
// NVIC_EnableIRQ(GPIO_IRQn);
|
|
|
|
return HM01B0_ERR_OK;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Deinitialize interfaces
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function deinitializes interfaces.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_deinit_if(hm01b0_cfg_t *psCfg)
|
|
{
|
|
am_hal_iom_disable(psCfg->pIOMHandle);
|
|
am_hal_iom_uninitialize(psCfg->pIOMHandle);
|
|
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinSCL, g_AM_HAL_GPIO_DISABLE);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinSDA, g_AM_HAL_GPIO_DISABLE);
|
|
|
|
// initialize pins for camera parallel interface.
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD0);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD1);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD2);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD3);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD4);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD5);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD6);
|
|
am_hal_gpio_fastgpio_disable(psCfg->ui8PinD7);
|
|
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD0);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD1);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD2);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD3);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD4);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD5);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD6);
|
|
am_hal_gpio_fastgpio_clr(psCfg->ui8PinD7);
|
|
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinVSYNC, g_AM_HAL_GPIO_DISABLE);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinHSYNC, g_AM_HAL_GPIO_DISABLE);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinPCLK, g_AM_HAL_GPIO_DISABLE);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinTrig, g_AM_HAL_GPIO_DISABLE);
|
|
am_hal_gpio_pinconfig(psCfg->ui8PinInt, g_AM_HAL_GPIO_DISABLE);
|
|
|
|
|
|
return HM01B0_ERR_OK;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Get HM01B0 Model ID
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param pui16MID - Pointer to buffer for the read back model ID.
|
|
//!
|
|
//! This function reads back HM01B0 model ID.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_get_modelid(hm01b0_cfg_t *psCfg, uint16_t *pui16MID)
|
|
{
|
|
uint8_t ui8Data[1];
|
|
uint32_t ui32Err;
|
|
|
|
*pui16MID = 0x0000;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_MODEL_ID_H, ui8Data, sizeof(ui8Data));
|
|
if (ui32Err == HM01B0_ERR_OK)
|
|
{
|
|
*pui16MID |= (ui8Data[0] << 8);
|
|
}
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_MODEL_ID_L, ui8Data, sizeof(ui8Data));
|
|
if (ui32Err == HM01B0_ERR_OK)
|
|
{
|
|
*pui16MID |= ui8Data[0];
|
|
}
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Initialize HM01B0
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param psScript - Pointer to HM01B0 initialization script.
|
|
//! @param ui32ScriptCmdNum - No. of commands in HM01B0 initialization script.
|
|
//!
|
|
//! This function initilizes HM01B0 with a given script.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_init_system(hm01b0_cfg_t *psCfg, hm_script_t *psScript, uint32_t ui32ScriptCmdNum)
|
|
{
|
|
return hm01b0_load_script(psCfg, psScript, ui32ScriptCmdNum);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Set HM01B0 in the walking 1s test mode
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function sets HM01B0 in the walking 1s test mode.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_test_walking1s(hm01b0_cfg_t *psCfg)
|
|
{
|
|
uint32_t ui32ScriptCmdNum = sizeof(sHM01b0TestModeScript_Walking1s) / sizeof(hm_script_t);
|
|
hm_script_t *psScript = (hm_script_t *)sHM01b0TestModeScript_Walking1s;
|
|
|
|
return hm01b0_load_script(psCfg, psScript, ui32ScriptCmdNum);
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Check the data read from HM01B0 in the walking 1s test mode
|
|
//!
|
|
//! @param pui8Buffer - Pointer to data buffer.
|
|
//! @param ui32BufferLen - Buffer length
|
|
//! @param ui32PrintCnt - Number of mismatched data to be printed out
|
|
//!
|
|
//! This function sets HM01B0 in the walking 1s test mode.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
void hm01b0_test_walking1s_check_data_sanity(uint8_t *pui8Buffer, uint32_t ui32BufferLen, uint32_t ui32PrintCnt)
|
|
{
|
|
uint8_t ui8ByteData = *pui8Buffer;
|
|
uint32_t ui32MismatchCnt = 0x00;
|
|
|
|
for (uint32_t ui32Idx = 0; ui32Idx < ui32BufferLen; ui32Idx++)
|
|
{
|
|
if (*(pui8Buffer + ui32Idx) != ui8ByteData)
|
|
{
|
|
if (ui32PrintCnt)
|
|
{
|
|
am_util_stdio_printf("[0x%08X] actual 0x%02X expected 0x%02X\n", ui32Idx, *(pui8Buffer + ui32Idx), ui8ByteData);
|
|
am_util_delay_ms(1);
|
|
ui32PrintCnt--;
|
|
}
|
|
ui32MismatchCnt++;
|
|
}
|
|
|
|
if (ui8ByteData)
|
|
ui8ByteData = ui8ByteData << 1;
|
|
else
|
|
ui8ByteData = 0x01;
|
|
}
|
|
|
|
am_util_stdio_printf("Mismatch Rate %d/%d\n", ui32MismatchCnt, ui32BufferLen);
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Software reset HM01B0
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! This function resets HM01B0 by issuing a reset command.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_reset_sw(hm01b0_cfg_t *psCfg)
|
|
{
|
|
uint8_t ui8Data[1] = {0x00};
|
|
return hm01b0_write_reg(psCfg, HM01B0_REG_SW_RESET, ui8Data, sizeof(ui8Data));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Get current HM01B0 operation mode.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param pui8Mode - Pointer to buffer
|
|
//! - for the read back operation mode to be put into
|
|
//!
|
|
//! This function get HM01B0 operation mode.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_get_mode(hm01b0_cfg_t *psCfg, uint8_t *pui8Mode)
|
|
{
|
|
uint8_t ui8Data[1] = {0x01};
|
|
uint32_t ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_MODE_SELECT, ui8Data, sizeof(ui8Data));
|
|
|
|
*pui8Mode = ui8Data[0];
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Set HM01B0 operation mode.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param ui8Mode - Operation mode. One of:
|
|
//! HM01B0_REG_MODE_SELECT_STANDBY
|
|
//! HM01B0_REG_MODE_SELECT_STREAMING
|
|
//! HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES
|
|
//! HM01B0_REG_MODE_SELECT_STREAMING_HW_TRIGGER
|
|
//! @param ui8FrameCnt - Frame count for HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES.
|
|
//! - Discarded if other modes.
|
|
//!
|
|
//! This function set HM01B0 operation mode.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_set_mode(hm01b0_cfg_t *psCfg, uint8_t ui8Mode, uint8_t ui8FrameCnt)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
|
|
if (ui8Mode == HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES)
|
|
{
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_PMU_PROGRAMMABLE_FRAMECNT, &ui8FrameCnt, sizeof(ui8FrameCnt));
|
|
}
|
|
|
|
if(ui32Err == HM01B0_ERR_OK)
|
|
{
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_MODE_SELECT, &ui8Mode, sizeof(ui8Mode));
|
|
}
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Activate the updated settings to HM01B0.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//!
|
|
//! Some settings updated to HM01B0 will only be affected after calling this function
|
|
//! 1. AE settings
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_cmd_update(hm01b0_cfg_t *psCfg)
|
|
{
|
|
uint8_t ui8Data = HM01B0_REG_GRP_PARAM_HOLD_HOLD;
|
|
|
|
return hm01b0_write_reg(psCfg, HM01B0_REG_GRP_PARAM_HOLD, &ui8Data, sizeof(ui8Data));
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Get HM01B0 AE convergance
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param psAECfg - Pointer to the structure hm01b0_ae_cfg_t.
|
|
//!
|
|
//! This function checks if AE is converged or not and returns ui32Err accordingly.
|
|
//! If caller needs detailed AE settings, psAECfg has to be non NULL.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_get_ae(hm01b0_cfg_t *psCfg, hm01b0_ae_cfg_t *psAECfg)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
uint8_t ui8AETargetMean;
|
|
uint8_t ui8AEMinMean;
|
|
uint8_t ui8AEMean;
|
|
uint8_t ui8ConvergeInTh;
|
|
uint8_t ui8ConvergeOutTh;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_AE_TARGET_MEAN, &ui8AETargetMean, sizeof(ui8AETargetMean));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_AE_MIN_MEAN, &ui8AEMinMean, sizeof(ui8AEMinMean));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_CONVERGE_IN_TH, &ui8ConvergeInTh, sizeof(ui8ConvergeInTh));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_CONVERGE_OUT_TH, &ui8ConvergeOutTh, sizeof(ui8ConvergeOutTh));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, 0x2020, &ui8AEMean, sizeof(ui8AEMean));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
if ((ui8AEMean < (ui8AETargetMean - ui8ConvergeInTh)) || (ui8AEMean > (ui8AETargetMean + ui8ConvergeInTh)))
|
|
ui32Err = HM01B0_ERR_AE_NOT_CONVERGED;
|
|
|
|
if (psAECfg)
|
|
{
|
|
psAECfg->ui8AETargetMean = ui8AETargetMean;
|
|
psAECfg->ui8AEMinMean = ui8AEMinMean;
|
|
psAECfg->ui8ConvergeInTh = ui8ConvergeInTh;
|
|
psAECfg->ui8ConvergeOutTh = ui8ConvergeOutTh;
|
|
psAECfg->ui8AEMean = ui8AEMean;
|
|
}
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief AE calibration.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param ui8CalFrames - Frame counts for calibratoin.
|
|
//! @param pui8Buffer - Pointer to the frame buffer.
|
|
//! @param ui32BufferLen - Framebuffer size.
|
|
//!
|
|
//! This function lets HM01B0 AE settled as much as possible within a given frame counts.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_cal_ae(hm01b0_cfg_t *psCfg, uint8_t ui8CalFrames, uint8_t *pui8Buffer, uint32_t ui32BufferLen)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
hm01b0_ae_cfg_t sAECfg;
|
|
|
|
am_util_stdio_printf("[%s] +\n", __func__);
|
|
|
|
hm01b0_set_mode(psCfg, HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES, ui8CalFrames);
|
|
|
|
for (uint8_t i = 0; i < ui8CalFrames; i++)
|
|
{
|
|
|
|
hm01b0_blocking_read_oneframe(psCfg, pui8Buffer, ui32BufferLen);
|
|
|
|
ui32Err = hm01b0_get_ae(psCfg, &sAECfg);
|
|
|
|
am_util_stdio_printf("AE Calibration(0x%02X) TargetMean 0x%02X, ConvergeInTh 0x%02X, AEMean 0x%02X\n", \
|
|
ui32Err, sAECfg.ui8AETargetMean, sAECfg.ui8ConvergeInTh, sAECfg.ui8AEMean);
|
|
|
|
// if AE calibration is done in ui8CalFrames, just exit to save some time.
|
|
if (ui32Err == HM01B0_ERR_OK)
|
|
break;
|
|
}
|
|
|
|
hm01b0_set_mode(psCfg, HM01B0_REG_MODE_SELECT_STANDBY, 0);
|
|
|
|
am_util_stdio_printf("[%s] -\n", __func__);
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Save HM01B0 exposure gain settings.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param psExpoGainCtrl - Pointer to the structure hm01b0_snr_expo_gain_ctrl_t
|
|
//!
|
|
//! This function saves HM01B0 exposure gain settings.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_save_exposure_gains(hm01b0_cfg_t *psCfg, hm01b0_snr_expo_gain_ctrl_t *psExpoGainCtrl)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
uint8_t ui8IntegrationH;
|
|
uint8_t ui8IntegrationL;
|
|
uint8_t ui8AGain;
|
|
uint8_t ui8DGain_H;
|
|
uint8_t ui8DGain_L;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_INTEGRATION_H, &ui8IntegrationH, sizeof(ui8IntegrationH));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_INTEGRATION_L, &ui8IntegrationL, sizeof(ui8IntegrationL));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_ANALOG_GAIN, &ui8AGain, sizeof(ui8AGain));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_H, &ui8DGain_H, sizeof(ui8DGain_H));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_L, &ui8DGain_L, sizeof(ui8DGain_L));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
if (psExpoGainCtrl)
|
|
{
|
|
psExpoGainCtrl->ui8IntegrationH = ui8IntegrationH;
|
|
psExpoGainCtrl->ui8IntegrationL = ui8IntegrationL;
|
|
psExpoGainCtrl->ui8AGain = ui8AGain;
|
|
psExpoGainCtrl->ui8DGain_H = ui8DGain_H;
|
|
psExpoGainCtrl->ui8DGain_L = ui8DGain_L;
|
|
}
|
|
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Restore HM01B0 exposure gain settings.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param psExpoGainCtrl - Pointer to the structure hm01b0_snr_expo_gain_ctrl_t
|
|
//!
|
|
//! This function restores HM01B0 exposure gain settings. The call flow shall be
|
|
//! hm01b0_restore_exposure_gains() -> hm01b0_cmd_update() -> hm01b0_set_mode()
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_restore_exposure_gains(hm01b0_cfg_t *psCfg, hm01b0_snr_expo_gain_ctrl_t *psExpoGainCtrl)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
uint8_t ui8Tmp;
|
|
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_INTEGRATION_H, &(psExpoGainCtrl->ui8IntegrationH), sizeof(psExpoGainCtrl->ui8IntegrationH));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_INTEGRATION_L, &(psExpoGainCtrl->ui8IntegrationL), sizeof(psExpoGainCtrl->ui8IntegrationL));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_ANALOG_GAIN, &ui8Tmp, sizeof(ui8Tmp));
|
|
ui8Tmp = (ui8Tmp & ~(0x7 << 4)) | (psExpoGainCtrl->ui8AGain & (0x7 << 4));
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_ANALOG_GAIN, &ui8Tmp, sizeof(ui8Tmp));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_H, &ui8Tmp, sizeof(ui8Tmp));
|
|
ui8Tmp = (ui8Tmp & ~(0x3 << 0)) | (psExpoGainCtrl->ui8DGain_H & (0x3 << 0));
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_H, &ui8Tmp, sizeof(ui8Tmp));
|
|
if (ui32Err != HM01B0_ERR_OK) return ui32Err;
|
|
|
|
ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_L, &ui8Tmp, sizeof(ui8Tmp));
|
|
ui8Tmp = (ui8Tmp & ~(0x3F << 2)) | (psExpoGainCtrl->ui8DGain_L & (0x3F << 2));
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_L, &ui8Tmp, sizeof(ui8Tmp));
|
|
|
|
return ui32Err;
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Hardware trigger HM01B0 to stream.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param bTrigger - True to start streaming
|
|
//! - False to stop streaming
|
|
//!
|
|
//! This function triggers HM01B0 to stream by toggling the TRIG pin.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_hardware_trigger_streaming(hm01b0_cfg_t *psCfg, bool bTrigger)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
uint8_t ui8Mode;
|
|
|
|
ui32Err = hm01b0_get_mode(psCfg, &ui8Mode);
|
|
|
|
if (ui32Err != HM01B0_ERR_OK)
|
|
goto end;
|
|
|
|
if (ui8Mode != HM01B0_REG_MODE_SELECT_STREAMING_HW_TRIGGER)
|
|
{
|
|
ui32Err = HM01B0_ERR_MODE;
|
|
goto end;
|
|
}
|
|
|
|
if (bTrigger)
|
|
{
|
|
am_hal_gpio_output_set(psCfg->ui8PinTrig);
|
|
}
|
|
else
|
|
{
|
|
am_hal_gpio_output_clear(psCfg->ui8PinTrig);
|
|
}
|
|
|
|
end:
|
|
return ui32Err;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Set HM01B0 mirror mode.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param bHmirror - Horizontal mirror
|
|
//! @param bVmirror - Vertical mirror
|
|
//!
|
|
//! This function set HM01B0 mirror mode.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_set_mirror(hm01b0_cfg_t *psCfg, bool bHmirror, bool bVmirror)
|
|
{
|
|
uint8_t ui8Data = 0x00;
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
|
|
if (bHmirror)
|
|
{
|
|
ui8Data |= HM01B0_REG_IMAGE_ORIENTATION_HMIRROR;
|
|
}
|
|
|
|
if (bVmirror)
|
|
{
|
|
ui8Data |= HM01B0_REG_IMAGE_ORIENTATION_VMIRROR;
|
|
}
|
|
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_IMAGE_ORIENTATION, &ui8Data, sizeof(ui8Data));
|
|
|
|
if (ui32Err == HM01B0_ERR_OK)
|
|
{
|
|
ui8Data = HM01B0_REG_GRP_PARAM_HOLD_HOLD;
|
|
ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_GRP_PARAM_HOLD, &ui8Data, sizeof(ui8Data));
|
|
}
|
|
|
|
return ui32Err;
|
|
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//
|
|
//! @brief Read data of one frame from HM01B0.
|
|
//!
|
|
//! @param psCfg - Pointer to HM01B0 configuration structure.
|
|
//! @param pui8Buffer - Pointer to the frame buffer.
|
|
//! @param ui32BufferLen - Framebuffer size.
|
|
//!
|
|
//! This function read data of one frame from HM01B0.
|
|
//!
|
|
//! @return Error code.
|
|
//
|
|
//*****************************************************************************
|
|
uint32_t hm01b0_blocking_read_oneframe(hm01b0_cfg_t *psCfg, uint8_t *pui8Buffer, uint32_t ui32BufferLen)
|
|
{
|
|
uint32_t ui32Err = HM01B0_ERR_OK;
|
|
uint32_t ui32Idx = 0x00;
|
|
|
|
am_util_stdio_printf("[%s] +\n", __func__);
|
|
|
|
uint32_t ui32HsyncCnt = 0x00;
|
|
|
|
while((ui32HsyncCnt < HM01B0_PIXEL_Y_NUM))
|
|
{
|
|
while (0x00 == read_hsync());
|
|
|
|
// read one row
|
|
while(read_hsync())
|
|
{
|
|
while(0x00 == read_pclk());
|
|
|
|
*(pui8Buffer + ui32Idx++) = read_byte();
|
|
|
|
if (ui32Idx == ui32BufferLen) {
|
|
goto end;
|
|
}
|
|
|
|
while(read_pclk());
|
|
}
|
|
|
|
ui32HsyncCnt++;
|
|
}
|
|
|
|
end:
|
|
am_util_stdio_printf("[%s] - Byte Counts %d\n", __func__, ui32Idx);
|
|
|
|
return ui32Err;
|
|
|
|
}
|