├── .gitattributes ├── .gitignore ├── examples └── Example1_StopMotion │ └── Example1_StopMotion.ino ├── keywords.txt ├── library.properties ├── src ├── hm01b0.c ├── hm01b0.h ├── hm01b0_arduino.cpp ├── hm01b0_arduino.h ├── hm01b0_platform.h ├── hm01b0_raw8_qvga_8bits_lsb_5fps.h ├── hm01b0_walking1s_01.h └── platforms │ ├── README.md │ ├── apollo3 │ ├── include │ │ └── hm01b0_platform_apollo3.h │ └── src │ │ ├── hm01b0_platform_apollo3 .cpp │ │ └── hm01b0_platform_apollo3.c │ └── arduino_generic │ └── include │ └── hm01b0_platform_arduino_generic.h └── utils ├── Example1_StopMotion.py ├── himax_script_convertor.py └── raw2bmp.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #VSCode 2 | *.vscode 3 | -------------------------------------------------------------------------------- /examples/Example1_StopMotion/Example1_StopMotion.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Saving camera stills over UART on SparkFun Edge board 3 | By: Owen Lyke 4 | SparkFun Electronics 5 | Date: November 18th 2019 6 | This example code is in the public domain 7 | 8 | SparkFun labored with love to create this code. Feel like supporting open source hardware? 9 | Buy a board from SparkFun! https://www.sparkfun.com/products/15170 10 | 11 | This example shows how to use the HM01B0 camera. It will stream frames captured by the 12 | camera over the UART. 13 | 14 | To see images: 15 | 1. upload this sketch (using baud 460800 is recommended) 16 | 2. navigate to the library folder (~/.../Arduino/libraries/SparkFun_Himax_HM01B0_Camera) 17 | 3. run the command 'python3 utils/Example1_StopMotion.py -p COM_PORT (COM_PORT is the same as the port used for upload in Arduino) 18 | 4. say "cheese" 19 | */ 20 | 21 | #include "hm01b0_arduino.h" 22 | #include "String.h" 23 | 24 | /////////////////// 25 | // Begin User Setup 26 | 27 | #define SERIAL_PORT Serial 28 | #define BAUD_RATE 460800 29 | 30 | //#define DEMO_HM01B0_TEST_MODE_ENABLE // Uncomment to enable test pattern generation 31 | //#define DEMO_HM01B0_FRAMEBUFFER_DUMP_ENABLE // Uncomment to enable frame output 32 | #define DEMO_HM01B0_PYTHON // Uncomment to use Python script to visualize data 33 | // (go to the sketch directory and use 'python3 utils/Example1_StopMotion.py -p {COM_PORT}' 34 | 35 | // End User Setup 36 | ///////////////// 37 | 38 | HM01B0 myCamera; // Declare an HM01B0 object called 'myCamera' 39 | // The camera will try to specialize for the host architecture 40 | // however it will fall back to a slow generic interface if no 41 | // specialization is available. 42 | // The default is not guaranteed to work due to the high amount 43 | // of data the camera needs to transfer 44 | 45 | 46 | // Auto-configure for python if requested 47 | #ifdef DEMO_HM01B0_PYTHON 48 | #define DEMO_HM01B0_FRAMEBUFFER_DUMP_ENABLE 49 | #undef DEMO_HM01B0_TEST_MODE_ENABLE 50 | #endif // DEMO_HM01B0_PYTHON 51 | 52 | // Forward declarations 53 | void printWord(uint32_t num); 54 | void printByte(uint8_t num); 55 | 56 | void setup() { 57 | 58 | // Start up serial monitor 59 | SERIAL_PORT.begin(BAUD_RATE); 60 | do { 61 | delay(500); 62 | }while(!SERIAL_PORT); 63 | 64 | // Turn on camera regulator if using Edge board 65 | #if defined (AM_BSP_GPIO_CAMERA_HM01B0_DVDDEN) 66 | pinMode(AM_BSP_GPIO_CAMERA_HM01B0_DVDDEN, OUTPUT); 67 | digitalWrite(AM_BSP_GPIO_CAMERA_HM01B0_DVDDEN, HIGH); 68 | SERIAL_PORT.println("Turned on camera regulator"); 69 | #endif 70 | 71 | // Start the camera 72 | if(myCamera.begin() != HM01B0_ERR_OK){ 73 | SERIAL_PORT.print("Camera.begin() failed with code: " + String(myCamera.status) + "\n"); 74 | }else{ 75 | SERIAL_PORT.print("Camera started successfully\n"); 76 | } 77 | 78 | // Calibrate Autoexposure 79 | SERIAL_PORT.println("Calibrating Auto Exposure..."); 80 | myCamera.calibrateAutoExposure(); 81 | if(myCamera.status != HM01B0_ERR_OK){ 82 | SERIAL_PORT.println("\tnot converged"); 83 | }else{ 84 | SERIAL_PORT.println("\tconverged!"); 85 | } 86 | 87 | #ifdef DEMO_HM01B0_TEST_MODE_ENABLE 88 | // Enable test mode (generates a 'walking 1s' pattern to verify interface function 89 | SERIAL_PORT.print("Enabling test mode...\n"); 90 | myCamera.enableTestMode(); 91 | if(myCamera.status != HM01B0_ERR_OK){ 92 | SERIAL_PORT.print("\tfailed\n"); 93 | }else{ 94 | SERIAL_PORT.print("\tsucceeded!\n"); 95 | } 96 | 97 | // In test mode capturing a frame fills the buffer with the test pattern 98 | myCamera.capture(); 99 | 100 | uint32_t mismatches = myCamera.countTestMismatches(); 101 | SERIAL_PORT.print("Self-test mismatches: 0x"); 102 | printWord(mismatches); 103 | SERIAL_PORT.print("\n"); 104 | #endif 105 | 106 | SERIAL_PORT.write(0x55); // Special character to sync Python script 107 | SERIAL_PORT.print("\n\n"); // Newlines allow Python script to find frame start 108 | } 109 | 110 | void loop() { 111 | // Take an image 112 | myCamera.capture(); 113 | 114 | #ifdef DEMO_HM01B0_FRAMEBUFFER_DUMP_ENABLE 115 | // Print out a frame for the Python script to pick up 116 | framebuffer_dump(); 117 | #else 118 | // Print auto exposure state 119 | SERIAL_PORT.print("AE convergance(0x"); 120 | printByte(myCamera.aeConvergenceStatus); 121 | SERIAL_PORT.print(") TargetMean 0x"); 122 | printByte(myCamera.aecfg.ui8AETargetMean); 123 | SERIAL_PORT.print(", ConvergeInTh 0x"); 124 | printByte(myCamera.aecfg.ui8ConvergeInTh); 125 | SERIAL_PORT.print(", AEMean 0x"); 126 | printByte(myCamera.aecfg.ui8AEMean); 127 | SERIAL_PORT.print("\n"); 128 | #endif 129 | 130 | 131 | // // Wait a second 132 | // delay(1000); 133 | } 134 | 135 | // 136 | // Utility functions 137 | 138 | // hex formating 139 | // Thanks to bootsector on the Arduino forums: 140 | // https://forum.arduino.cc/index.php?topic=38107.msg282336#msg282336 141 | void printWord(uint32_t num) { 142 | char tmp[9]; // 8 hex digits + null terminator 143 | sprintf(tmp, "%08X", num); 144 | SERIAL_PORT.print(tmp); 145 | } 146 | 147 | void printByte(uint8_t num) { 148 | char tmp[3]; // 2 hex digits + null terminator 149 | sprintf(tmp, "%02X", num); 150 | SERIAL_PORT.print(tmp); 151 | } 152 | 153 | // frame buffer dump (formatted for python script) 154 | void framebuffer_dump( void ){ 155 | SERIAL_PORT.print("+++ frame +++"); // Mark frame start 156 | for (uint32_t ui32Idx = 0; ui32Idx < myCamera.frameBufferSize; ui32Idx++){ // Process all bytes in frame 157 | if ((ui32Idx & 0xF) == 0x00){ // Print address every 16 bytes 158 | SERIAL_PORT.print("\n0x"); 159 | printWord(ui32Idx); 160 | SERIAL_PORT.print(" "); 161 | } 162 | printByte(myCamera.frameBuffer[ui32Idx]); // Print byte value 163 | SERIAL_PORT.print(" "); 164 | } 165 | SERIAL_PORT.print("\n--- frame ---\n"); 166 | memset(myCamera.frameBuffer, 0x00, sizeof(myCamera.frameBufferSize)); // Zero out frame buffer for help identifying errors 167 | } 168 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | 10 | ####################################### 11 | # Methods and Functions (KEYWORD2) 12 | ####################################### 13 | 14 | HM01B0 KEYWORD2 15 | begin KEYWORD2 16 | calibrateAutoExposure KEYWORD2 17 | enableTestMode KEYWORD2 18 | countTestMismatches KEYWORD2 19 | capture KEYWORD2 20 | getAutoExposureStatus KEYWORD2 21 | end KEYWORD2 22 | 23 | ####################################### 24 | # Constants (LITERAL1) 25 | ####################################### 26 | 27 | _HM01B0_H_ LITERAL1 28 | extern LITERAL1 29 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun Himax HM01B0 Camera 2 | version=0.0.3 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=Configure and use the Himax HM01B0 camera module 6 | paragraph=Configure and use the Himax HM01B0 camera module. Defines an API that specialized interfaces may use to control the camera 7 | category=Sensors 8 | url=https://github.com/sparkfun/SparkFun_HM01B0_Camera_ArduinoLibrary 9 | architectures=* 10 | depends= 11 | -------------------------------------------------------------------------------- /src/hm01b0.c: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // 3 | //! @file HM01B0.c 4 | //! 5 | // Original work by Larry Tien - AmbiqMicro 6 | // Generalization by Owen Lyke - SparkFun Electronics (2019) 7 | // 8 | //***************************************************************************** 9 | 10 | #include "hm01b0.h" 11 | #include "hm01b0_walking1s_01.h" 12 | #include "hm01b0_platform.h" 13 | 14 | //***************************************************************************** 15 | // 16 | //! @brief Write HM01B0 registers 17 | //! 18 | //! @param psCfg - Pointer to HM01B0 configuration structure. 19 | //! @param ui16Reg - Register address. 20 | //! @param pui8Value - Pointer to the data to be written. 21 | //! @param ui32NumBytes - Length of the data in bytes to be written. 22 | //! @param arg - user assignable pointer (input) 23 | //! 24 | //! This function writes value to HM01B0 registers. 25 | //! 26 | //! @return Error code. 27 | // 28 | //***************************************************************************** 29 | hm01b0_status_e hm01b0_write_reg(hm01b0_cfg_t *psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes){ 30 | if(psCfg->interface->write != NULL){ 31 | return psCfg->interface->write(psCfg, ui16Reg, pui8Value, ui32NumBytes, psCfg->interface->arg); 32 | }else{ 33 | return HM01B0_ERR_UNIMPLEMENTED; 34 | } 35 | } 36 | 37 | //***************************************************************************** 38 | // 39 | //! @brief Read HM01B0 registers 40 | //! 41 | //! @param psCfg - Pointer to HM01B0 configuration structure. 42 | //! @param ui16Reg - Register address. 43 | //! @param pui8Value - Pointer to the buffer for read data to be put into. 44 | //! @param ui32NumBytes - Length of the data to be read. 45 | //! @param arg - user assignable pointer (input) 46 | //! 47 | //! This function reads value from HM01B0 registers. 48 | //! 49 | //! @return Error code. 50 | // 51 | //***************************************************************************** 52 | hm01b0_status_e hm01b0_read_reg(hm01b0_cfg_t *psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes){ 53 | if(psCfg->interface->read != NULL){ 54 | return psCfg->interface->read(psCfg, ui16Reg, pui8Value, ui32NumBytes, psCfg->interface->arg); 55 | }else{ 56 | return HM01B0_ERR_UNIMPLEMENTED; 57 | } 58 | } 59 | 60 | //***************************************************************************** 61 | // 62 | //! @brief Load HM01B0 a given script 63 | //! 64 | //! @param psCfg - Pointer to HM01B0 configuration structure. 65 | //! @param psScrip - Pointer to the script to be loaded. 66 | //! @param ui32ScriptCmdNum - Number of entries in a given script. 67 | //! 68 | //! This function loads HM01B0 a given script. 69 | //! 70 | //! @return Error code. 71 | // 72 | //***************************************************************************** 73 | hm01b0_status_e hm01b0_load_script(hm01b0_cfg_t *psCfg, hm_script_t *psScript, uint32_t ui32ScriptCmdNum) 74 | { 75 | hm01b0_status_e ui32Err = HM01B0_ERR_OK; 76 | for (uint32_t idx = 0; idx < ui32ScriptCmdNum; idx++) 77 | { 78 | ui32Err = hm01b0_write_reg(psCfg, (psScript + idx)->ui16Reg, &((psScript + idx)->ui8Val), sizeof(uint8_t)); 79 | if (ui32Err != HM01B0_ERR_OK) 80 | { 81 | break; 82 | } 83 | } 84 | return ui32Err; 85 | } 86 | 87 | //***************************************************************************** 88 | // 89 | //! @brief Power up HM01B0 90 | //! 91 | //! @param psCfg - Pointer to HM01B0 configuration structure. 92 | //! 93 | //! This function powers up HM01B0. 94 | //! 95 | //! @return Error code. 96 | // 97 | //***************************************************************************** 98 | hm01b0_status_e hm01b0_power_up(hm01b0_cfg_t *psCfg) 99 | { 100 | hm01b0_status_e retval = HM01B0_ERR_OK; 101 | // place holder 102 | (void)(psCfg); 103 | return retval; 104 | } 105 | 106 | //***************************************************************************** 107 | // 108 | //! @brief Power down HM01B0 109 | //! 110 | //! @param psCfg - Pointer to HM01B0 configuration structure. 111 | //! 112 | //! This function powers up HM01B0. 113 | //! 114 | //! @return none. 115 | // 116 | //***************************************************************************** 117 | hm01b0_status_e hm01b0_power_down(hm01b0_cfg_t *psCfg) 118 | { 119 | hm01b0_status_e retval = HM01B0_ERR_OK; 120 | // place holder 121 | (void)(psCfg); 122 | return retval; 123 | } 124 | 125 | //***************************************************************************** 126 | // 127 | //! @brief Enable MCLK 128 | //! 129 | //! @param psCfg - Pointer to HM01B0 configuration structure. 130 | //! 131 | //! This function utilizes CTimer to generate MCLK for HM01B0. 132 | //! 133 | //! @return none. 134 | // 135 | //***************************************************************************** 136 | hm01b0_status_e hm01b0_mclk_enable(hm01b0_cfg_t *psCfg) 137 | { 138 | if(psCfg->interface->mclk != NULL){ 139 | return psCfg->interface->mclk(psCfg, true, psCfg->interface->arg); 140 | }else{ 141 | return HM01B0_ERR_UNIMPLEMENTED; 142 | } 143 | } 144 | 145 | //***************************************************************************** 146 | // 147 | //! @brief Disable MCLK 148 | //! 149 | //! @param psCfg - Pointer to HM01B0 configuration structure. 150 | //! 151 | //! This function disable CTimer to stop MCLK for HM01B0. 152 | //! 153 | //! @return none. 154 | // 155 | //***************************************************************************** 156 | hm01b0_status_e hm01b0_mclk_disable(hm01b0_cfg_t *psCfg) 157 | { 158 | if(psCfg->interface->mclk != NULL){ 159 | return psCfg->interface->mclk(psCfg, false, psCfg->interface->arg); 160 | }else{ 161 | return HM01B0_ERR_UNIMPLEMENTED; 162 | } 163 | } 164 | 165 | //***************************************************************************** 166 | // 167 | //! @brief Initialize interfaces 168 | //! 169 | //! @param psCfg - Pointer to HM01B0 configuration structure. 170 | //! 171 | //! This function initializes interfaces. 172 | //! 173 | //! @return Error code. 174 | // 175 | //***************************************************************************** 176 | hm01b0_status_e hm01b0_init_if(hm01b0_cfg_t *psCfg) 177 | { 178 | if(psCfg->interface->init != NULL){ 179 | return psCfg->interface->init(psCfg, psCfg->interface->arg); 180 | }else{ 181 | return HM01B0_ERR_UNIMPLEMENTED; 182 | } 183 | } 184 | 185 | //***************************************************************************** 186 | // 187 | //! @brief Deinitialize interfaces 188 | //! 189 | //! @param psCfg - Pointer to HM01B0 configuration structure. 190 | //! 191 | //! This function deinitializes interfaces. 192 | //! 193 | //! @return Error code. 194 | // 195 | //***************************************************************************** 196 | hm01b0_status_e hm01b0_deinit_if(hm01b0_cfg_t *psCfg) 197 | { 198 | if(psCfg->interface->deinit != NULL){ 199 | return psCfg->interface->deinit(psCfg, psCfg->interface->arg); 200 | }else{ 201 | return HM01B0_ERR_UNIMPLEMENTED; 202 | } 203 | } 204 | 205 | //***************************************************************************** 206 | // 207 | //! @brief Get HM01B0 Model ID 208 | //! 209 | //! @param psCfg - Pointer to HM01B0 configuration structure. 210 | //! @param pui16MID - Pointer to buffer for the read back model ID. 211 | //! 212 | //! This function reads back HM01B0 model ID. 213 | //! 214 | //! @return Error code. 215 | // 216 | //***************************************************************************** 217 | hm01b0_status_e hm01b0_get_modelid(hm01b0_cfg_t *psCfg, uint16_t *pui16MID) 218 | { 219 | uint8_t ui8Data[1]; 220 | hm01b0_status_e ui32Err; 221 | 222 | *pui16MID = 0x0000; 223 | 224 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_MODEL_ID_H, ui8Data, sizeof(ui8Data)); 225 | if (ui32Err == HM01B0_ERR_OK) 226 | { 227 | *pui16MID |= (ui8Data[0] << 8); 228 | } 229 | 230 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_MODEL_ID_L, ui8Data, sizeof(ui8Data)); 231 | if (ui32Err == HM01B0_ERR_OK) 232 | { 233 | *pui16MID |= ui8Data[0]; 234 | } 235 | 236 | return ui32Err; 237 | } 238 | 239 | //***************************************************************************** 240 | // 241 | //! @brief Initialize HM01B0 242 | //! 243 | //! @param psCfg - Pointer to HM01B0 configuration structure. 244 | //! @param psScript - Pointer to HM01B0 initialization script. 245 | //! @param ui32ScriptCmdNum - No. of commands in HM01B0 initialization script. 246 | //! 247 | //! This function initilizes HM01B0 with a given script. 248 | //! 249 | //! @return Error code. 250 | // 251 | //***************************************************************************** 252 | hm01b0_status_e hm01b0_init_system(hm01b0_cfg_t *psCfg, hm_script_t *psScript, uint32_t ui32ScriptCmdNum) 253 | { 254 | return hm01b0_load_script(psCfg, psScript, ui32ScriptCmdNum); 255 | } 256 | 257 | //***************************************************************************** 258 | // 259 | //! @brief Set HM01B0 in the walking 1s test mode 260 | //! 261 | //! @param psCfg - Pointer to HM01B0 configuration structure. 262 | //! 263 | //! This function sets HM01B0 in the walking 1s test mode. 264 | //! 265 | //! @return Error code. 266 | // 267 | //***************************************************************************** 268 | hm01b0_status_e hm01b0_test_walking1s(hm01b0_cfg_t *psCfg) 269 | { 270 | uint32_t ui32ScriptCmdNum = sizeof(sHM01b0TestModeScript_Walking1s) / sizeof(hm_script_t); 271 | hm_script_t *psScript = (hm_script_t *)sHM01b0TestModeScript_Walking1s; 272 | 273 | return hm01b0_load_script(psCfg, psScript, ui32ScriptCmdNum); 274 | } 275 | 276 | //***************************************************************************** 277 | // 278 | //! @brief Check the data read from HM01B0 in the walking 1s test mode 279 | //! 280 | //! @param pui8Buffer - Pointer to data buffer. 281 | //! @param ui32BufferLen - Buffer length 282 | //! @param ui32PrintCnt - Number of mismatched data to be printed out 283 | //! 284 | //! This function sets HM01B0 in the walking 1s test mode. 285 | //! 286 | //! @return Mismatch count 287 | // 288 | //***************************************************************************** 289 | uint32_t hm01b0_test_walking1s_check_data_sanity(uint8_t *pui8Buffer, uint32_t ui32BufferLen) 290 | { 291 | uint8_t ui8ByteData = *pui8Buffer; 292 | uint32_t ui32MismatchCnt = 0x00; 293 | 294 | for (uint32_t ui32Idx = 0; ui32Idx < ui32BufferLen; ui32Idx++) 295 | { 296 | if (*(pui8Buffer + ui32Idx) != ui8ByteData) 297 | { 298 | ui32MismatchCnt++; 299 | } 300 | 301 | if (ui8ByteData) 302 | ui8ByteData = ui8ByteData << 1; 303 | else 304 | ui8ByteData = 0x01; 305 | } 306 | return ui32MismatchCnt; 307 | } 308 | 309 | //***************************************************************************** 310 | // 311 | //! @brief Software reset HM01B0 312 | //! 313 | //! @param psCfg - Pointer to HM01B0 configuration structure. 314 | //! 315 | //! This function resets HM01B0 by issuing a reset command. 316 | //! 317 | //! @return Error code. 318 | // 319 | //***************************************************************************** 320 | hm01b0_status_e hm01b0_reset_sw(hm01b0_cfg_t *psCfg) 321 | { 322 | uint8_t ui8Data[1] = {0x00}; 323 | return hm01b0_write_reg(psCfg, HM01B0_REG_SW_RESET, ui8Data, sizeof(ui8Data)); 324 | } 325 | 326 | //***************************************************************************** 327 | // 328 | //! @brief Get current HM01B0 operation mode. 329 | //! 330 | //! @param psCfg - Pointer to HM01B0 configuration structure. 331 | //! @param pui8Mode - Pointer to buffer 332 | //! - for the read back operation mode to be put into 333 | //! 334 | //! This function get HM01B0 operation mode. 335 | //! 336 | //! @return Error code. 337 | // 338 | //***************************************************************************** 339 | hm01b0_status_e hm01b0_get_mode(hm01b0_cfg_t *psCfg, uint8_t *pui8Mode) 340 | { 341 | uint8_t ui8Data[1] = {0x01}; 342 | uint32_t ui32Err; 343 | 344 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_MODE_SELECT, ui8Data, sizeof(ui8Data)); 345 | 346 | *pui8Mode = ui8Data[0]; 347 | 348 | return ui32Err; 349 | } 350 | 351 | //***************************************************************************** 352 | // 353 | //! @brief Set HM01B0 operation mode. 354 | //! 355 | //! @param psCfg - Pointer to HM01B0 configuration structure. 356 | //! @param ui8Mode - Operation mode. One of: 357 | //! HM01B0_REG_MODE_SELECT_STANDBY 358 | //! HM01B0_REG_MODE_SELECT_STREAMING 359 | //! HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES 360 | //! HM01B0_REG_MODE_SELECT_STREAMING_HW_TRIGGER 361 | //! @param ui8FrameCnt - Frame count for HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES. 362 | //! - Discarded if other modes. 363 | //! 364 | //! This function set HM01B0 operation mode. 365 | //! 366 | //! @return Error code. 367 | // 368 | //***************************************************************************** 369 | hm01b0_status_e hm01b0_set_mode(hm01b0_cfg_t *psCfg, uint8_t ui8Mode, uint8_t ui8FrameCnt) 370 | { 371 | uint32_t ui32Err = HM01B0_ERR_OK; 372 | 373 | if (ui8Mode == HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES) 374 | { 375 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_PMU_PROGRAMMABLE_FRAMECNT, &ui8FrameCnt, sizeof(ui8FrameCnt)); 376 | } 377 | 378 | if(ui32Err == HM01B0_ERR_OK) 379 | { 380 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_MODE_SELECT, &ui8Mode, sizeof(ui8Mode)); 381 | } 382 | 383 | return ui32Err; 384 | } 385 | 386 | //***************************************************************************** 387 | // 388 | //! @brief Activate the updated settings to HM01B0. 389 | //! 390 | //! @param psCfg - Pointer to HM01B0 configuration structure. 391 | //! 392 | //! Some settings updated to HM01B0 will only be affected after calling this function 393 | //! 1. AE settings 394 | //! 395 | //! @return Error code. 396 | // 397 | //***************************************************************************** 398 | hm01b0_status_e hm01b0_cmd_update(hm01b0_cfg_t *psCfg) 399 | { 400 | uint8_t ui8Data = HM01B0_REG_GRP_PARAM_HOLD_HOLD; 401 | 402 | return hm01b0_write_reg(psCfg, HM01B0_REG_GRP_PARAM_HOLD, &ui8Data, sizeof(ui8Data)); 403 | } 404 | 405 | //***************************************************************************** 406 | // 407 | //! @brief Get HM01B0 AE convergance 408 | //! 409 | //! @param psCfg - Pointer to HM01B0 configuration structure. 410 | //! @param psAECfg - Pointer to the structure hm01b0_ae_cfg_t. 411 | //! 412 | //! This function checks if AE is converged or not and returns ui32Err accordingly. 413 | //! If caller needs detailed AE settings, psAECfg has to be non NULL. 414 | //! 415 | //! @return Error code. 416 | // 417 | //***************************************************************************** 418 | hm01b0_status_e hm01b0_get_ae(hm01b0_cfg_t *psCfg, hm01b0_ae_cfg_t *psAECfg) 419 | { 420 | uint32_t ui32Err = HM01B0_ERR_OK; 421 | uint8_t ui8AETargetMean; 422 | uint8_t ui8AEMinMean; 423 | uint8_t ui8AEMean; 424 | uint8_t ui8ConvergeInTh; 425 | uint8_t ui8ConvergeOutTh; 426 | 427 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_AE_TARGET_MEAN, &ui8AETargetMean, sizeof(ui8AETargetMean)); 428 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 429 | 430 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_AE_MIN_MEAN, &ui8AEMinMean, sizeof(ui8AEMinMean)); 431 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 432 | 433 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_CONVERGE_IN_TH, &ui8ConvergeInTh, sizeof(ui8ConvergeInTh)); 434 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 435 | 436 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_CONVERGE_OUT_TH, &ui8ConvergeOutTh, sizeof(ui8ConvergeOutTh)); 437 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 438 | 439 | ui32Err = hm01b0_read_reg(psCfg, 0x2020, &ui8AEMean, sizeof(ui8AEMean)); 440 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 441 | 442 | if ((ui8AEMean < (ui8AETargetMean - ui8ConvergeInTh)) || (ui8AEMean > (ui8AETargetMean + ui8ConvergeInTh))) 443 | ui32Err = HM01B0_ERR_AE_NOT_CONVERGED; 444 | 445 | if (psAECfg) 446 | { 447 | psAECfg->ui8AETargetMean = ui8AETargetMean; 448 | psAECfg->ui8AEMinMean = ui8AEMinMean; 449 | psAECfg->ui8ConvergeInTh = ui8ConvergeInTh; 450 | psAECfg->ui8ConvergeOutTh = ui8ConvergeOutTh; 451 | psAECfg->ui8AEMean = ui8AEMean; 452 | } 453 | 454 | return ui32Err; 455 | } 456 | 457 | //***************************************************************************** 458 | // 459 | //! @brief AE calibration. 460 | //! 461 | //! @param psCfg - Pointer to HM01B0 configuration structure. 462 | //! @param ui8CalFrames - Frame counts for calibratoin. 463 | //! @param pui8Buffer - Pointer to the frame buffer. 464 | //! @param ui32BufferLen - Framebuffer size. 465 | //! @param pAECfg - Pointer to AECfg structure to fill with calibration results 466 | //! 467 | //! This function lets HM01B0 AE settled as much as possible within a given frame counts. 468 | //! 469 | //! @return Error code. 470 | // 471 | //***************************************************************************** 472 | hm01b0_status_e hm01b0_cal_ae(hm01b0_cfg_t *psCfg, uint8_t ui8CalFrames, uint8_t *pui8Buffer, uint32_t ui32BufferLen, hm01b0_ae_cfg_t* pAECfg) 473 | { 474 | uint32_t ui32Err = HM01B0_ERR_OK; 475 | if(pAECfg == NULL){ 476 | return HM01B0_ERR_PARAMS; 477 | } 478 | 479 | hm01b0_set_mode(psCfg, HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES, ui8CalFrames); 480 | 481 | for (uint8_t i = 0; i < ui8CalFrames; i++) 482 | { 483 | 484 | hm01b0_blocking_read_oneframe(psCfg, pui8Buffer, ui32BufferLen); 485 | 486 | ui32Err = hm01b0_get_ae(psCfg, pAECfg); 487 | 488 | // // todo: could report out intermediate results here (without using printing - perhaps a callback function) 489 | // SERIAL_PORT.printf("AE Calibration(0x%02X) TargetMean 0x%02X, ConvergeInTh 0x%02X, AEMean 0x%02X\n", 490 | // ui32Err, sAECfg.ui8AETargetMean, sAECfg.ui8ConvergeInTh, sAECfg.ui8AEMean); 491 | 492 | // if AE calibration is done in ui8CalFrames, just exit to save some time. 493 | if (ui32Err == HM01B0_ERR_OK) 494 | break; 495 | } 496 | 497 | hm01b0_set_mode(psCfg, HM01B0_REG_MODE_SELECT_STANDBY, 0); 498 | 499 | return ui32Err; 500 | } 501 | 502 | 503 | //***************************************************************************** 504 | // 505 | //! @brief Save HM01B0 exposure gain settings. 506 | //! 507 | //! @param psCfg - Pointer to HM01B0 configuration structure. 508 | //! @param psExpoGainCtrl - Pointer to the structure hm01b0_snr_expo_gain_ctrl_t 509 | //! 510 | //! This function saves HM01B0 exposure gain settings. 511 | //! 512 | //! @return Error code. 513 | // 514 | //***************************************************************************** 515 | hm01b0_status_e hm01b0_save_exposure_gains(hm01b0_cfg_t *psCfg, hm01b0_snr_expo_gain_ctrl_t *psExpoGainCtrl) 516 | { 517 | uint32_t ui32Err = HM01B0_ERR_OK; 518 | uint8_t ui8IntegrationH; 519 | uint8_t ui8IntegrationL; 520 | uint8_t ui8AGain; 521 | uint8_t ui8DGain_H; 522 | uint8_t ui8DGain_L; 523 | 524 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_INTEGRATION_H, &ui8IntegrationH, sizeof(ui8IntegrationH)); 525 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 526 | 527 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_INTEGRATION_L, &ui8IntegrationL, sizeof(ui8IntegrationL)); 528 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 529 | 530 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_ANALOG_GAIN, &ui8AGain, sizeof(ui8AGain)); 531 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 532 | 533 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_H, &ui8DGain_H, sizeof(ui8DGain_H)); 534 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 535 | 536 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_L, &ui8DGain_L, sizeof(ui8DGain_L)); 537 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 538 | 539 | if (psExpoGainCtrl) 540 | { 541 | psExpoGainCtrl->ui8IntegrationH = ui8IntegrationH; 542 | psExpoGainCtrl->ui8IntegrationL = ui8IntegrationL; 543 | psExpoGainCtrl->ui8AGain = ui8AGain; 544 | psExpoGainCtrl->ui8DGain_H = ui8DGain_H; 545 | psExpoGainCtrl->ui8DGain_L = ui8DGain_L; 546 | } 547 | 548 | return ui32Err; 549 | } 550 | 551 | //***************************************************************************** 552 | // 553 | //! @brief Restore HM01B0 exposure gain settings. 554 | //! 555 | //! @param psCfg - Pointer to HM01B0 configuration structure. 556 | //! @param psExpoGainCtrl - Pointer to the structure hm01b0_snr_expo_gain_ctrl_t 557 | //! 558 | //! This function restores HM01B0 exposure gain settings. The call flow shall be 559 | //! hm01b0_restore_exposure_gains() -> hm01b0_cmd_update() -> hm01b0_set_mode() 560 | //! 561 | //! @return Error code. 562 | // 563 | //***************************************************************************** 564 | hm01b0_status_e hm01b0_restore_exposure_gains(hm01b0_cfg_t *psCfg, hm01b0_snr_expo_gain_ctrl_t *psExpoGainCtrl) 565 | { 566 | uint32_t ui32Err = HM01B0_ERR_OK; 567 | uint8_t ui8Tmp; 568 | 569 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_INTEGRATION_H, &(psExpoGainCtrl->ui8IntegrationH), sizeof(psExpoGainCtrl->ui8IntegrationH)); 570 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 571 | 572 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_INTEGRATION_L, &(psExpoGainCtrl->ui8IntegrationL), sizeof(psExpoGainCtrl->ui8IntegrationL)); 573 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 574 | 575 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_ANALOG_GAIN, &ui8Tmp, sizeof(ui8Tmp)); 576 | ui8Tmp = (ui8Tmp & ~(0x7 << 4)) | (psExpoGainCtrl->ui8AGain & (0x7 << 4)); 577 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_ANALOG_GAIN, &ui8Tmp, sizeof(ui8Tmp)); 578 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 579 | 580 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_H, &ui8Tmp, sizeof(ui8Tmp)); 581 | ui8Tmp = (ui8Tmp & ~(0x3 << 0)) | (psExpoGainCtrl->ui8DGain_H & (0x3 << 0)); 582 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_H, &ui8Tmp, sizeof(ui8Tmp)); 583 | if (ui32Err != HM01B0_ERR_OK) return ui32Err; 584 | 585 | ui32Err = hm01b0_read_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_L, &ui8Tmp, sizeof(ui8Tmp)); 586 | ui8Tmp = (ui8Tmp & ~(0x3F << 2)) | (psExpoGainCtrl->ui8DGain_L & (0x3F << 2)); 587 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_DIGITAL_GAIN_L, &ui8Tmp, sizeof(ui8Tmp)); 588 | 589 | return ui32Err; 590 | 591 | } 592 | 593 | //***************************************************************************** 594 | // 595 | //! @brief Hardware trigger HM01B0 to stream. 596 | //! 597 | //! @param psCfg - Pointer to HM01B0 configuration structure. 598 | //! @param bTrigger - True to start streaming 599 | //! - False to stop streaming 600 | //! 601 | //! This function triggers HM01B0 to stream by toggling the TRIG pin. 602 | //! 603 | //! @return Error code. 604 | // 605 | //***************************************************************************** 606 | hm01b0_status_e hm01b0_hardware_trigger_streaming(hm01b0_cfg_t *psCfg, bool bTrigger) 607 | { 608 | uint32_t ui32Err = HM01B0_ERR_OK; 609 | uint8_t ui8Mode; 610 | 611 | if(psCfg->interface->trig == NULL){ 612 | ui32Err = HM01B0_ERR_UNIMPLEMENTED; 613 | goto end; 614 | } 615 | 616 | ui32Err = hm01b0_get_mode(psCfg, &ui8Mode); 617 | 618 | if (ui32Err != HM01B0_ERR_OK) 619 | goto end; 620 | 621 | if (ui8Mode != HM01B0_REG_MODE_SELECT_STREAMING_HW_TRIGGER) 622 | { 623 | ui32Err = HM01B0_ERR_MODE; 624 | goto end; 625 | } 626 | 627 | if (bTrigger) 628 | { 629 | ui32Err = psCfg->interface->trig(psCfg, true, psCfg->interface->arg); 630 | } 631 | else 632 | { 633 | ui32Err = psCfg->interface->trig(psCfg, false, psCfg->interface->arg); 634 | } 635 | 636 | end: 637 | return ui32Err; 638 | } 639 | 640 | //***************************************************************************** 641 | // 642 | //! @brief Set HM01B0 mirror mode. 643 | //! 644 | //! @param psCfg - Pointer to HM01B0 configuration structure. 645 | //! @param bHmirror - Horizontal mirror 646 | //! @param bVmirror - Vertical mirror 647 | //! 648 | //! This function set HM01B0 mirror mode. 649 | //! 650 | //! @return Error code. 651 | // 652 | //***************************************************************************** 653 | hm01b0_status_e hm01b0_set_mirror(hm01b0_cfg_t *psCfg, bool bHmirror, bool bVmirror) 654 | { 655 | uint8_t ui8Data = 0x00; 656 | uint32_t ui32Err = HM01B0_ERR_OK; 657 | 658 | if (bHmirror) 659 | { 660 | ui8Data |= HM01B0_REG_IMAGE_ORIENTATION_HMIRROR; 661 | } 662 | 663 | if (bVmirror) 664 | { 665 | ui8Data |= HM01B0_REG_IMAGE_ORIENTATION_VMIRROR; 666 | } 667 | 668 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_IMAGE_ORIENTATION, &ui8Data, sizeof(ui8Data)); 669 | 670 | if (ui32Err == HM01B0_ERR_OK) 671 | { 672 | ui8Data = HM01B0_REG_GRP_PARAM_HOLD_HOLD; 673 | ui32Err = hm01b0_write_reg(psCfg, HM01B0_REG_GRP_PARAM_HOLD, &ui8Data, sizeof(ui8Data)); 674 | } 675 | 676 | return ui32Err; 677 | 678 | } 679 | 680 | //***************************************************************************** 681 | // 682 | //! @brief Read data of one frame from HM01B0. 683 | //! 684 | //! @param psCfg - Pointer to HM01B0 configuration structure. 685 | //! @param pui8Buffer - Pointer to the frame buffer. 686 | //! @param ui32BufferLen - Framebuffer size. 687 | //! 688 | //! This function read data of one frame from HM01B0. 689 | //! 690 | //! @return Error code. 691 | // 692 | //***************************************************************************** 693 | hm01b0_status_e hm01b0_blocking_read_oneframe(hm01b0_cfg_t *psCfg, uint8_t *pui8Buffer, uint32_t ui32BufferLen) 694 | { 695 | (void)(psCfg); 696 | uint32_t ui32Err = HM01B0_ERR_OK; 697 | uint32_t ui32Idx = 0x00; 698 | 699 | uint32_t ui32HsyncCnt = 0x00; 700 | 701 | while((ui32HsyncCnt < HM01B0_PIXEL_Y_NUM)) 702 | { 703 | while (0x00 == HM01B0_READ_HSYNC); 704 | 705 | // read one row 706 | while(HM01B0_READ_HSYNC) 707 | { 708 | while(0x00 == HM01B0_READ_PCLK); 709 | 710 | *(pui8Buffer + ui32Idx++) = HM01B0_READ_BYTE; 711 | 712 | if (ui32Idx == ui32BufferLen) { 713 | goto end; 714 | } 715 | 716 | while(HM01B0_READ_PCLK); 717 | } 718 | 719 | ui32HsyncCnt++; 720 | } 721 | 722 | end: 723 | return ui32Err; 724 | 725 | } 726 | -------------------------------------------------------------------------------- /src/hm01b0.h: -------------------------------------------------------------------------------- 1 | //***************************************************************************** 2 | // 3 | //! @file HM01B0_C.h 4 | // 5 | //***************************************************************************** 6 | #ifndef HM01B0_C_H 7 | #define HM01B0_C_H 8 | 9 | #include "stdint.h" 10 | #include "stdbool.h" 11 | #include "stdlib.h" 12 | 13 | #ifdef __cplusplus 14 | extern "C" 15 | { 16 | #endif 17 | 18 | #define HM01B0_DRV_VERSION (0) 19 | #define HM01B0_DRV_SUBVERSION (5) 20 | 21 | #define HM01B0_DEFAULT_ADDRESS (0x24) 22 | 23 | #define HM01B0_PIXEL_X_NUM (324) 24 | #define HM01B0_PIXEL_Y_NUM (244) 25 | 26 | #define HM01B0_REG_MODEL_ID_H (0x0000) 27 | #define HM01B0_REG_MODEL_ID_L (0x0001) 28 | #define HM01B0_REG_SILICON_REV (0x0002) 29 | #define HM01B0_REG_FRAME_COUNT (0x0005) 30 | #define HM01B0_REG_PIXEL_ORDER (0x0006) 31 | 32 | #define HM01B0_REG_MODE_SELECT (0x0100) 33 | #define HM01B0_REG_IMAGE_ORIENTATION (0x0101) 34 | #define HM01B0_REG_SW_RESET (0x0103) 35 | #define HM01B0_REG_GRP_PARAM_HOLD (0x0104) 36 | 37 | #define HM01B0_REG_INTEGRATION_H (0x0202) 38 | #define HM01B0_REG_INTEGRATION_L (0x0203) 39 | #define HM01B0_REG_ANALOG_GAIN (0x0205) 40 | #define HM01B0_REG_DIGITAL_GAIN_H (0x020E) 41 | #define HM01B0_REG_DIGITAL_GAIN_L (0x020F) 42 | 43 | #define HM01B0_REG_AE_TARGET_MEAN (0x2101) 44 | #define HM01B0_REG_AE_MIN_MEAN (0x2102) 45 | #define HM01B0_REG_CONVERGE_IN_TH (0x2103) 46 | #define HM01B0_REG_CONVERGE_OUT_TH (0x2104) 47 | 48 | 49 | #define HM01B0_REG_I2C_ID_SEL (0x3400) 50 | #define HM01B0_REG_I2C_ID_REG (0x3401) 51 | 52 | #define HM01B0_REG_PMU_PROGRAMMABLE_FRAMECNT (0x3020) 53 | 54 | // #define HM01B0_REG_MODE_SELECT (0x0100) 55 | #define HM01B0_REG_MODE_SELECT_STANDBY (0x00) 56 | #define HM01B0_REG_MODE_SELECT_STREAMING (0x01) 57 | #define HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES (0x03) 58 | #define HM01B0_REG_MODE_SELECT_STREAMING_HW_TRIGGER (0x05) 59 | 60 | // #define HM01B0_REG_IMAGE_ORIENTATION (0x0101) 61 | #define HM01B0_REG_IMAGE_ORIENTATION_DEFAULT (0x00) 62 | #define HM01B0_REG_IMAGE_ORIENTATION_HMIRROR (0x01) 63 | #define HM01B0_REG_IMAGE_ORIENTATION_VMIRROR (0x02) 64 | #define HM01B0_REG_IMAGE_ORIENTATION_HVMIRROR (HM01B0_REG_IMAGE_ORIENTATION_HMIRROR | HM01B0_REG_IMAGE_ORIENTATION_HVMIRROR) 65 | 66 | // #define HM01B0_REG_GRP_PARAM_HOLD (0x0104) 67 | #define HM01B0_REG_GRP_PARAM_HOLD_CONSUME (0x00) 68 | #define HM01B0_REG_GRP_PARAM_HOLD_HOLD (0x01) 69 | 70 | #define HM01B0_MODEL_ID (0x01B0) 71 | 72 | // forward declarations 73 | typedef struct _hm01b0_cfg_t hm01b0_cfg_t; 74 | 75 | typedef enum { 76 | HM01B0_ERR_OK = 0x00, 77 | HM01B0_ERR, 78 | HM01B0_ERR_I2C, 79 | HM01B0_ERR_MODE, 80 | HM01B0_ERR_AE_NOT_CONVERGED, 81 | HM01B0_ERR_MCLK, 82 | HM01B0_ERR_INIT, 83 | HM01B0_ERR_DEINIT, 84 | HM01B0_ERR_PARAMS, 85 | HM01B0_ERR_UNIMPLEMENTED, 86 | 87 | HM01B0_NUM_ERR 88 | } hm01b0_status_e; 89 | 90 | typedef hm01b0_status_e (*hm01b0_if_fn_t)(hm01b0_cfg_t* psCfg, void* arg); 91 | typedef hm01b0_status_e (*hm01b0_if_i2c_fn_t)(hm01b0_cfg_t* psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes, void* arg); 92 | typedef hm01b0_status_e (*hm01b0_if_on_off_fn_t)(hm01b0_cfg_t* psCfg, bool enable, void* arg); 93 | typedef struct { 94 | hm01b0_if_fn_t init; // any initialization code needed 95 | hm01b0_if_i2c_fn_t write; // write to registers over I2C 96 | hm01b0_if_i2c_fn_t read; // read from registers over I2C 97 | hm01b0_if_on_off_fn_t mclk; // enable/disable the clock generation hardware 98 | hm01b0_if_on_off_fn_t trig; // enable/disabe the trigger pin 99 | hm01b0_if_fn_t deinit; // any deinitialization code needed 100 | void* arg; // argument for the user available in interface functions 101 | } hm01b0_if_t; // abstracts the interface for the HM01B0 102 | 103 | typedef struct 104 | { 105 | uint16_t ui16Reg; 106 | uint8_t ui8Val; 107 | } hm_script_t; 108 | 109 | struct _hm01b0_cfg_t { 110 | 111 | hm01b0_if_t* interface; 112 | }; 113 | 114 | typedef struct 115 | { 116 | uint8_t ui8AETargetMean; 117 | uint8_t ui8AEMinMean; 118 | uint8_t ui8ConvergeInTh; 119 | uint8_t ui8ConvergeOutTh; 120 | uint8_t ui8AEMean; 121 | } hm01b0_ae_cfg_t; 122 | 123 | typedef struct 124 | { 125 | uint8_t ui8IntegrationH; 126 | uint8_t ui8IntegrationL; 127 | uint8_t ui8AGain; 128 | uint8_t ui8DGain_H; 129 | uint8_t ui8DGain_L; 130 | } hm01b0_snr_expo_gain_ctrl_t; 131 | 132 | //***************************************************************************** 133 | // 134 | //! @brief Write HM01B0 registers 135 | //! 136 | //! @param psCfg - Pointer to HM01B0 configuration structure. 137 | //! @param ui16Reg - Register address. 138 | //! @param pui8Value - Pointer to the data to be written. 139 | //! @param ui32NumBytes - Length of the data in bytes to be written. 140 | //! 141 | //! This function writes value to HM01B0 registers. 142 | //! 143 | //! @return Error code. 144 | // 145 | //***************************************************************************** 146 | hm01b0_status_e hm01b0_write_reg(hm01b0_cfg_t *psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes); 147 | 148 | //***************************************************************************** 149 | // 150 | //! @brief Read HM01B0 registers 151 | //! 152 | //! @param psCfg - Pointer to HM01B0 configuration structure. 153 | //! @param ui16Reg - Register address. 154 | //! @param pui8Value - Pointer to the buffer for read data to be put into. 155 | //! @param ui32NumBytes - Length of the data to be read. 156 | //! 157 | //! This function reads value from HM01B0 registers. 158 | //! 159 | //! @return Error code. 160 | // 161 | //***************************************************************************** 162 | hm01b0_status_e hm01b0_read_reg(hm01b0_cfg_t *psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes); 163 | 164 | //***************************************************************************** 165 | // 166 | //! @brief Load HM01B0 a given script 167 | //! 168 | //! @param psCfg - Pointer to HM01B0 configuration structure. 169 | //! @param psScrip - Pointer to the script to be loaded. 170 | //! @param ui32ScriptCmdNum - Number of entries in a given script. 171 | //! 172 | //! This function loads HM01B0 a given script. 173 | //! 174 | //! @return Error code. 175 | // 176 | //***************************************************************************** 177 | hm01b0_status_e hm01b0_load_script(hm01b0_cfg_t *psCfg, hm_script_t *psScript, uint32_t ui32ScriptCmdNum); 178 | 179 | //***************************************************************************** 180 | // 181 | //! @brief Power up HM01B0 182 | //! 183 | //! @param psCfg - Pointer to HM01B0 configuration structure. 184 | //! 185 | //! This function powers up HM01B0. 186 | //! 187 | //! @return Error code. 188 | // 189 | //***************************************************************************** 190 | hm01b0_status_e hm01b0_power_up(hm01b0_cfg_t *psCfg); 191 | 192 | //***************************************************************************** 193 | // 194 | //! @brief Power down HM01B0 195 | //! 196 | //! @param psCfg - Pointer to HM01B0 configuration structure. 197 | //! 198 | //! This function powers up HM01B0. 199 | //! 200 | //! @return Error code. 201 | // 202 | //***************************************************************************** 203 | hm01b0_status_e hm01b0_power_down(hm01b0_cfg_t *psCfg); 204 | 205 | //***************************************************************************** 206 | // 207 | //! @brief Enable MCLK 208 | //! 209 | //! @param psCfg - Pointer to HM01B0 configuration structure. 210 | //! 211 | //! This function utilizes CTimer to generate MCLK for HM01B0. 212 | //! 213 | //! @return Error code. 214 | // 215 | //***************************************************************************** 216 | hm01b0_status_e hm01b0_mclk_enable(hm01b0_cfg_t *psCfg); 217 | 218 | //***************************************************************************** 219 | // 220 | //! @brief Disable MCLK 221 | //! 222 | //! @param psCfg - Pointer to HM01B0 configuration structure. 223 | //! 224 | //! This function disable CTimer to stop MCLK for HM01B0. 225 | //! 226 | //! @return Error code. 227 | // 228 | //***************************************************************************** 229 | hm01b0_status_e hm01b0_mclk_disable(hm01b0_cfg_t *psCfg); 230 | 231 | //***************************************************************************** 232 | // 233 | //! @brief Initialize interfaces 234 | //! 235 | //! @param psCfg - Pointer to HM01B0 configuration structure. 236 | //! 237 | //! This function initializes interfaces. 238 | //! 239 | //! @return Error code. 240 | // 241 | //***************************************************************************** 242 | hm01b0_status_e hm01b0_init_if(hm01b0_cfg_t *psCfg); 243 | 244 | //***************************************************************************** 245 | // 246 | //! @brief Deinitialize interfaces 247 | //! 248 | //! @param psCfg - Pointer to HM01B0 configuration structure. 249 | //! 250 | //! This function deinitializes interfaces. 251 | //! 252 | //! @return Error code. 253 | // 254 | //***************************************************************************** 255 | hm01b0_status_e hm01b0_deinit_if(hm01b0_cfg_t *psCfg); 256 | 257 | //***************************************************************************** 258 | // 259 | //! @brief Get HM01B0 Model ID 260 | //! 261 | //! @param psCfg - Pointer to HM01B0 configuration structure. 262 | //! @param pui16MID - Pointer to buffer for the read back model ID. 263 | //! 264 | //! This function reads back HM01B0 model ID. 265 | //! 266 | //! @return Error code. 267 | // 268 | //***************************************************************************** 269 | hm01b0_status_e hm01b0_get_modelid(hm01b0_cfg_t *psCfg, uint16_t *pui16MID); 270 | 271 | //***************************************************************************** 272 | // 273 | //! @brief Initialize HM01B0 274 | //! 275 | //! @param psCfg - Pointer to HM01B0 configuration structure. 276 | //! @param psScript - Pointer to HM01B0 initialization script. 277 | //! @param ui32ScriptCmdNum - No. of commands in HM01B0 initialization script. 278 | //! 279 | //! This function initilizes HM01B0 with a given script. 280 | //! 281 | //! @return Error code. 282 | // 283 | //***************************************************************************** 284 | hm01b0_status_e hm01b0_init_system(hm01b0_cfg_t *psCfg, hm_script_t *psScript, uint32_t ui32ScriptCmdNum); 285 | 286 | //***************************************************************************** 287 | // 288 | //! @brief Set HM01B0 in the walking 1s test mode 289 | //! 290 | //! @param psCfg - Pointer to HM01B0 configuration structure. 291 | //! 292 | //! This function sets HM01B0 in the walking 1s test mode. 293 | //! 294 | //! @return Error code. 295 | // 296 | //***************************************************************************** 297 | hm01b0_status_e hm01b0_test_walking1s(hm01b0_cfg_t *psCfg); 298 | 299 | //***************************************************************************** 300 | // 301 | //! @brief Check the data read from HM01B0 in the walking 1s test mode 302 | //! 303 | //! @param pui8Buffer - Pointer to data buffer. 304 | //! @param ui32BufferLen - Buffer length 305 | //! 306 | //! This function sets HM01B0 in the walking 1s test mode. 307 | //! 308 | //! @return Mismatch count. 309 | // 310 | //***************************************************************************** 311 | uint32_t hm01b0_test_walking1s_check_data_sanity(uint8_t *pui8Buffer, uint32_t ui32BufferLen); 312 | 313 | //***************************************************************************** 314 | // 315 | //! @brief Software reset HM01B0 316 | //! 317 | //! @param psCfg - Pointer to HM01B0 configuration structure. 318 | //! 319 | //! This function resets HM01B0 by issuing a reset command. 320 | //! 321 | //! @return Error code. 322 | // 323 | //***************************************************************************** 324 | hm01b0_status_e hm01b0_reset_sw(hm01b0_cfg_t *psCfg); 325 | 326 | //***************************************************************************** 327 | // 328 | //! @brief Get current HM01B0 operation mode. 329 | //! 330 | //! @param psCfg - Pointer to HM01B0 configuration structure. 331 | //! @param pui8Mode - Pointer to buffer 332 | //! - for the read back operation mode to be put into 333 | //! 334 | //! This function get HM01B0 operation mode. 335 | //! 336 | //! @return Error code. 337 | // 338 | //***************************************************************************** 339 | hm01b0_status_e hm01b0_get_mode(hm01b0_cfg_t *psCfg, uint8_t *pui8Mode); 340 | 341 | //***************************************************************************** 342 | // 343 | //! @brief Set HM01B0 operation mode. 344 | //! 345 | //! @param psCfg - Pointer to HM01B0 configuration structure. 346 | //! @param ui8Mode - Operation mode. One of: 347 | //! HM01B0_REG_MODE_SELECT_STANDBY 348 | //! HM01B0_REG_MODE_SELECT_STREAMING 349 | //! HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES 350 | //! HM01B0_REG_MODE_SELECT_STREAMING_HW_TRIGGER 351 | //! @param framecnt - Frame count for HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES. 352 | //! - Discarded if other modes. 353 | //! 354 | //! This function set HM01B0 operation mode. 355 | //! 356 | //! @return Error code. 357 | // 358 | //***************************************************************************** 359 | hm01b0_status_e hm01b0_set_mode(hm01b0_cfg_t *psCfg, uint8_t ui8Mode, uint8_t framecnt); 360 | 361 | 362 | //***************************************************************************** 363 | // 364 | //! @brief Activate the updated settings to HM01B0. 365 | //! 366 | //! @param psCfg - Pointer to HM01B0 configuration structure. 367 | //! 368 | //! Some settings updated to HM01B0 will only be affected after calling this function 369 | //! 1. AE settings 370 | //! 371 | //! @return Error code. 372 | // 373 | //***************************************************************************** 374 | hm01b0_status_e hm01b0_cmd_update(hm01b0_cfg_t *psCfg); 375 | 376 | //***************************************************************************** 377 | // 378 | //! @brief Get HM01B0 AE settings 379 | //! 380 | //! @param psCfg - Pointer to HM01B0 configuration structure. 381 | //! @param psAECfg - Pointer to the structure hm01b0_ae_cfg_t. 382 | //! 383 | //! This function checks if AE is converged or not and returns ui32Err accordingly. 384 | //! If caller needs detailed AE settings, psAECfg has to be non NULL. 385 | //! 386 | //! @return Error code. 387 | // 388 | //***************************************************************************** 389 | hm01b0_status_e hm01b0_get_ae(hm01b0_cfg_t *psCfg, hm01b0_ae_cfg_t *psAECfg); 390 | 391 | //***************************************************************************** 392 | // 393 | //! @brief AE calibration. 394 | //! 395 | //! @param psCfg - Pointer to HM01B0 configuration structure. 396 | //! @param ui8CalFrames - Frame counts for calibratoin. 397 | //! @param pui8Buffer - Pointer to the frame buffer. 398 | //! @param ui32BufferLen - Framebuffer size. 399 | //! @param pAECfg - Pointer to hm01b0_ae_cfg_t structure to fill with calibration results 400 | //! 401 | //! This function lets HM01B0 AE settled as much as possible within a given frame counts. 402 | //! 403 | //! @return Error code. 404 | // 405 | //***************************************************************************** 406 | hm01b0_status_e hm01b0_cal_ae(hm01b0_cfg_t *psCfg, uint8_t ui8CalFrames, uint8_t *pui8Buffer, uint32_t ui32BufferLen, hm01b0_ae_cfg_t* pAECfg ); 407 | 408 | //***************************************************************************** 409 | // 410 | //! @brief Save HM01B0 exposure gain settings. 411 | //! 412 | //! @param psCfg - Pointer to HM01B0 configuration structure. 413 | //! @param psExpoGainCtrl - Pointer to the structure hm01b0_snr_expo_gain_ctrl_t 414 | //! 415 | //! This function saves HM01B0 exposure gain settings. 416 | //! 417 | //! @return Error code. 418 | // 419 | //***************************************************************************** 420 | hm01b0_status_e hm01b0_save_exposure_gains(hm01b0_cfg_t *psCfg, hm01b0_snr_expo_gain_ctrl_t *psExpoGainCtrl); 421 | 422 | //***************************************************************************** 423 | // 424 | //! @brief Restore HM01B0 exposure gain settings. 425 | //! 426 | //! @param psCfg - Pointer to HM01B0 configuration structure. 427 | //! @param psExpoGainCtrl - Pointer to the structure hm01b0_snr_expo_gain_ctrl_t 428 | //! 429 | //! This function restores HM01B0 exposure gain settings. The call flow shall be 430 | //! hm01b0_restore_exposure_gains() -> hm01b0_cmd_update() -> hm01b0_set_mode() 431 | //! 432 | //! @return Error code. 433 | // 434 | //***************************************************************************** 435 | hm01b0_status_e hm01b0_restore_exposure_gains(hm01b0_cfg_t *psCfg, hm01b0_snr_expo_gain_ctrl_t *psExpoGainCtrl); 436 | 437 | //***************************************************************************** 438 | // 439 | //! @brief Hardware trigger HM01B0 to stream. 440 | //! 441 | //! @param psCfg - Pointer to HM01B0 configuration structure. 442 | //! @param bTrigger - True to start streaming 443 | //! - False to stop streaming 444 | //! 445 | //! This function triggers HM01B0 to stream by toggling the TRIG pin. 446 | //! 447 | //! @return Error code. 448 | // 449 | //***************************************************************************** 450 | hm01b0_status_e HM01B0_C_Hardware_trigger_streaming(hm01b0_cfg_t *psCfg, bool bTrigger); 451 | 452 | //***************************************************************************** 453 | // 454 | //! @brief Set HM01B0 mirror mode. 455 | //! 456 | //! @param psCfg - Pointer to HM01B0 configuration structure. 457 | //! @param bHmirror - Horizontal mirror 458 | //! @param bVmirror - Vertical mirror 459 | //! 460 | //! This function set HM01B0 mirror mode. 461 | //! 462 | //! @return Error code. 463 | // 464 | //***************************************************************************** 465 | hm01b0_status_e hm01b0_set_mirror(hm01b0_cfg_t *psCfg, bool bHmirror, bool bVmirror); 466 | 467 | 468 | //***************************************************************************** 469 | // 470 | //! @brief Read data of one frame from HM01B0. 471 | //! 472 | //! @param psCfg - Pointer to HM01B0 configuration structure. 473 | //! @param pui8Buffer - Pointer to the frame buffer. 474 | //! @param ui32BufferLen - Framebuffer size. 475 | //! 476 | //! This function read data of one frame from HM01B0. 477 | //! 478 | //! @return Error code. 479 | // 480 | //***************************************************************************** 481 | hm01b0_status_e hm01b0_blocking_read_oneframe(hm01b0_cfg_t *psCfg, \ 482 | uint8_t *pui8Buffer, uint32_t ui32BufferLen); 483 | 484 | #ifdef __cplusplus 485 | } 486 | #endif 487 | 488 | #endif // AM_HAL_CTIMER_H 489 | -------------------------------------------------------------------------------- /src/hm01b0_arduino.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #include "hm01b0_arduino.h" 24 | #include "hm01b0_raw8_qvga_8bits_lsb_5fps.h" 25 | 26 | 27 | 28 | void framebuffer_dump(uint8_t *pui8Buffer, uint32_t ui32BufferLen); 29 | 30 | HM01B0::HM01B0(hm01b0_cfg_t _cfg){ 31 | cfg = _cfg; 32 | memset((void*)&aecfg, 0x00, sizeof(hm01b0_ae_cfg_t)); 33 | } 34 | 35 | hm01b0_status_e HM01B0::begin( void ){ 36 | uint16_t ui16ModelId = 0x0000; 37 | 38 | status = hm01b0_mclk_enable(&cfg); 39 | if(status != HM01B0_ERR_OK){ goto fail; } 40 | 41 | status = hm01b0_init_if(&cfg); 42 | if(status != HM01B0_ERR_OK){ goto fail; } 43 | 44 | status = hm01b0_get_modelid(&cfg, &ui16ModelId); 45 | if( ui16ModelId != (uint16_t)HM01B0_MODEL_ID ){ status = HM01B0_ERR; } 46 | if(status != HM01B0_ERR_OK){ goto deinit; } 47 | 48 | hm01b0_init_system(&cfg, (hm_script_t *)sHM01B0InitScript, sizeof(sHM01B0InitScript)/sizeof(hm_script_t)); 49 | 50 | return status; 51 | 52 | deinit: 53 | hm01b0_deinit_if(&cfg); 54 | 55 | fail: 56 | return status; 57 | } 58 | 59 | hm01b0_status_e HM01B0::calibrateAutoExposure( void ){ 60 | status = hm01b0_cal_ae(&cfg, 10, frameBuffer, sizeof(frameBuffer), &aecfg); 61 | return status; 62 | } 63 | 64 | hm01b0_status_e HM01B0::enableTestMode( void ){ 65 | status = hm01b0_test_walking1s(&cfg); 66 | return status; 67 | } 68 | 69 | uint32_t HM01B0::countTestMismatches( void ){ 70 | uint32_t mismatches = 0; 71 | mismatches = hm01b0_test_walking1s_check_data_sanity(frameBuffer, sizeof(frameBuffer)); 72 | return mismatches; 73 | } 74 | 75 | hm01b0_status_e HM01B0::capture( void ){ 76 | hm01b0_status_e retval = HM01B0_ERR_OK; 77 | uint8_t ui8Mode = 0xFF; 78 | 79 | getAutoExposureStatus(); 80 | hm01b0_get_mode(&cfg, &ui8Mode); 81 | // Serial.printf("HM01B0 current mode %d\n", ui8Mode); 82 | 83 | hm01b0_cmd_update(&cfg); 84 | hm01b0_set_mode(&cfg, HM01B0_REG_MODE_SELECT_STREAMING_NFRAMES, 1); 85 | hm01b0_blocking_read_oneframe(&cfg, frameBuffer, sizeof(frameBuffer)); 86 | 87 | return retval; 88 | } 89 | 90 | void HM01B0::getAutoExposureStatus( void ){ 91 | aeConvergenceStatus = hm01b0_get_ae(&cfg, &aecfg); 92 | } 93 | 94 | hm01b0_status_e HM01B0::end( void ){ 95 | hm01b0_status_e retval = HM01B0_ERR_OK; 96 | 97 | hm01b0_deinit_if(&cfg); 98 | hm01b0_mclk_disable(&cfg); 99 | 100 | return retval; 101 | } 102 | -------------------------------------------------------------------------------- /src/hm01b0_arduino.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef _HM01B0_ARDUINO_H_ 24 | #define _HM01B0_ARDUINO_H_ 25 | 26 | #include "Arduino.h" 27 | #include "hm01b0.h" 28 | 29 | // #define 30 | 31 | extern hm01b0_cfg_t hm01b0_cfg; // This must be provided by the platform 32 | 33 | class HM01B0 { 34 | private: 35 | 36 | public: 37 | protected: 38 | hm01b0_cfg_t cfg = {0}; 39 | 40 | public: 41 | hm01b0_status_e status = HM01B0_ERR_OK; 42 | hm01b0_status_e aeConvergenceStatus = HM01B0_ERR_OK; 43 | static const size_t frameBufferSize = ((size_t)HM01B0_PIXEL_X_NUM * (size_t)HM01B0_PIXEL_Y_NUM); 44 | uint8_t frameBuffer[frameBufferSize] = {0}; 45 | hm01b0_ae_cfg_t aecfg; 46 | 47 | HM01B0(hm01b0_cfg_t _cfg = hm01b0_cfg); 48 | 49 | hm01b0_status_e begin( void ); 50 | hm01b0_status_e calibrateAutoExposure( void ); 51 | hm01b0_status_e enableTestMode( void ); 52 | uint32_t countTestMismatches( void ); 53 | hm01b0_status_e capture( void ); 54 | void getAutoExposureStatus( void ); 55 | hm01b0_status_e end( void ); 56 | }; 57 | 58 | 59 | 60 | #endif // _HM01B0_ARDUINO_H_ 61 | -------------------------------------------------------------------------------- /src/hm01b0_platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef _HM01B0_PLATFORM_H_ 24 | 25 | // Conditionally Include Platforms 26 | #if defined (AM_PART_APOLLO3) && \ 27 | defined (ARDUINO_SFE_EDGE) 28 | #include "platforms/apollo3/include/hm01b0_platform_apollo3.h" 29 | #else 30 | #warning "No platform implementation - falling back to generic Arduino interface. Performance not guaranteed." 31 | #include "platforms/arduino_generic/include/hm01b0_platform_arduino_generic.h" 32 | #endif // platform inclusion 33 | 34 | #ifndef HM01B0_READ_HSYNC 35 | #warning HM01B0_READ_HSYNC undefined! 36 | #define HM01B0_READ_HSYNC 0 37 | #endif 38 | 39 | #ifndef HM01B0_READ_PCLK 40 | #warning HM01B0_READ_PCLK undefined! 41 | #define HM01B0_READ_PCLK 0 42 | #endif 43 | 44 | #ifndef HM01B0_READ_BYTE 45 | #warning HM01B0_READ_BYTE undefined! 46 | #define HM01B0_READ_BYTE 0 47 | #endif 48 | 49 | #endif // _HM01B0_PLATFORM_H_ -------------------------------------------------------------------------------- /src/hm01b0_raw8_qvga_8bits_lsb_5fps.h: -------------------------------------------------------------------------------- 1 | const hm_script_t sHM01B0InitScript[] = 2 | { 3 | // ;************************************************************************* 4 | // ; Sensor: HM01B0 5 | // ; I2C ID: 24 6 | // ; Resolution: 324x244 7 | // ; Lens: 8 | // ; Flicker: 9 | // ; Frequency: 10 | // ; Description: AE control enable 11 | // ; 8-bit mode, LSB first 12 | // ; 13 | // ; 14 | // ; Note: 15 | // ; 16 | // ; $Revision: 1338 $ 17 | // ; $Date:: 2017-04-11 15:43:45 +0800#$ 18 | // ;************************************************************************* 19 | // 20 | // // --------------------------------------------------- 21 | // // HUB system initial 22 | // // --------------------------------------------------- 23 | // W 20 8A04 01 2 1 24 | // W 20 8A00 22 2 1 25 | // W 20 8A01 00 2 1 26 | // W 20 8A02 01 2 1 27 | // W 20 0035 93 2 1 ; [3]&[1] hub616 20bits in, [5:4]=1 mclk=48/2=24mhz 28 | // W 20 0036 00 2 1 29 | // W 20 0011 09 2 1 30 | // W 20 0012 B6 2 1 31 | // W 20 0014 08 2 1 32 | // W 20 0015 98 2 1 33 | // ;W 20 0130 16 2 1 ; 3m soc, signal buffer control 34 | // ;W 20 0100 44 2 1 ; [6] hub616 20bits in 35 | // W 20 0100 04 2 1 ; [6] hub616 20bits in 36 | // W 20 0121 01 2 1 ; [0] Q1 Intf enable, [1]:4bit mode, [2] msb first, [3] serial mode 37 | // W 20 0150 00 2 1 ; 38 | // W 20 0150 04 2 1 ; 39 | // 40 | // 41 | // //--------------------------------------------------- 42 | // // Initial 43 | // //--------------------------------------------------- 44 | // W 24 0103 00 2 1 ; software reset-> was 0x22 45 | {0x0103, 0x00,}, 46 | // W 24 0100 00 2 1; power up 47 | {0x0100, 0x00,}, 48 | // 49 | // 50 | // 51 | // //--------------------------------------------------- 52 | // // Analog 53 | // //--------------------------------------------------- 54 | // L HM01B0_analog_setting.txt 55 | {0x1003, 0x08,}, 56 | {0x1007, 0x08,}, 57 | {0x3044, 0x0A,}, 58 | {0x3045, 0x00,}, 59 | {0x3047, 0x0A,}, 60 | {0x3050, 0xC0,}, 61 | {0x3051, 0x42,}, 62 | {0x3052, 0x50,}, 63 | {0x3053, 0x00,}, 64 | {0x3054, 0x03,}, 65 | {0x3055, 0xF7,}, 66 | {0x3056, 0xF8,}, 67 | {0x3057, 0x29,}, 68 | {0x3058, 0x1F,}, 69 | {0x3059, 0x1E,}, 70 | {0x3064, 0x00,}, 71 | {0x3065, 0x04,}, 72 | // 73 | // 74 | // //--------------------------------------------------- 75 | // // Digital function 76 | // //--------------------------------------------------- 77 | // 78 | // // BLC 79 | // W 24 1000 43 2 1 ; BLC_on, IIR 80 | {0x1000, 0x43,}, 81 | // W 24 1001 40 2 1 ; [6] : BLC dithering en 82 | {0x1001, 0x40,}, 83 | // W 24 1002 32 2 1 ; // blc_darkpixel_thd 84 | {0x1002, 0x32,}, 85 | // 86 | // // Dgain 87 | // W 24 0350 7F 2 1 ; Dgain Control 88 | {0x0350, 0x7F,}, 89 | // 90 | // // BLI 91 | // W 24 1006 01 2 1 ; [0] : bli enable 92 | {0x1006, 0x01,}, 93 | // 94 | // // DPC 95 | // W 24 1008 00 2 1 ; [2:0] : DPC option 0: DPC off 1 : mono 3 : bayer1 5 : bayer2 96 | {0x1008, 0x00,}, 97 | // W 24 1009 A0 2 1 ; cluster hot pixel th 98 | {0x1009, 0xA0,}, 99 | // W 24 100A 60 2 1 ; cluster cold pixel th 100 | {0x100A, 0x60,}, 101 | // W 24 100B 90 2 1 ; single hot pixel th 102 | {0x100B, 0x90,}, 103 | // W 24 100C 40 2 1 ; single cold pixel th 104 | {0x100C, 0x40,}, 105 | // // 106 | // advance VSYNC by 1 row 107 | {0x3022, 0x01,}, 108 | // W 24 1012 00 2 1 ; Sync. enable VSYNC shift 109 | {0x1012, 0x01,}, 110 | 111 | // 112 | // // ROI Statistic 113 | // W 24 2000 07 2 1 ; [0] : AE stat en [1] : MD LROI stat en [2] : MD GROI stat en [3] : RGB stat ratio en [4] : IIR selection (1 -> 16, 0 -> 8) 114 | {0x2000, 0x07,}, 115 | // W 24 2003 00 2 1 ; MD GROI 0 y start HB 116 | {0x2003, 0x00,}, 117 | // W 24 2004 1C 2 1 ; MD GROI 0 y start LB 118 | {0x2004, 0x1C,}, 119 | // W 24 2007 00 2 1 ; MD GROI 1 y start HB 120 | {0x2007, 0x00,}, 121 | // W 24 2008 58 2 1 ; MD GROI 1 y start LB 122 | {0x2008, 0x58,}, 123 | // W 24 200B 00 2 1 ; MD GROI 2 y start HB 124 | {0x200B, 0x00,}, 125 | // W 24 200C 7A 2 1 ; MD GROI 2 y start LB 126 | {0x200C, 0x7A,}, 127 | // W 24 200F 00 2 1 ; MD GROI 3 y start HB 128 | {0x200F, 0x00,}, 129 | // W 24 2010 B8 2 1 ; MD GROI 3 y start LB 130 | {0x2010, 0xB8,}, 131 | // 132 | // W 24 2013 00 2 1 ; MD LRIO y start HB 133 | {0x2013, 0x00,}, 134 | // W 24 2014 58 2 1 ; MD LROI y start LB 135 | {0x2014, 0x58,}, 136 | // W 24 2017 00 2 1 ; MD LROI y end HB 137 | {0x2017, 0x00,}, 138 | // W 24 2018 9B 2 1 ; MD LROI y end LB 139 | {0x2018, 0x9B,}, 140 | // 141 | // // AE 142 | // W 24 2100 01 2 1 ; [0]: AE control enable 143 | {0x2100, 0x01,}, 144 | // W 24 2104 07 2 1 ; converge out th 145 | {0x2104, 0x07,}, 146 | // W 24 2105 0C 2 1 ; max INTG Hb 147 | {0x2105, 0x0C,}, 148 | // W 24 2106 78 2 1 ; max INTG Lb 149 | {0x2106, 0x78,}, 150 | // W 24 2108 03 2 1 ; max AGain in full 151 | {0x2108, 0x03,}, 152 | // W 24 2109 03 2 1 ; max AGain in bin2 153 | {0x2109, 0x03,}, 154 | // W 24 210B 80 2 1 ; max DGain 155 | {0x210B, 0x80,}, 156 | // W 24 210F 00 2 1 ; FS 60Hz Hb 157 | {0x210F, 0x00,}, 158 | // W 24 2110 85 2 1 ; FS 60Hz Lb 159 | {0x2110, 0x85,}, 160 | // W 24 2111 00 2 1 ; Fs 50Hz Hb 161 | {0x2111, 0x00,}, 162 | // W 24 2112 A0 2 1 ; FS 50Hz Lb 163 | {0x2112, 0xA0,}, 164 | // 165 | // 166 | // // MD 167 | // W 24 2150 03 2 1 ; [0] : MD LROI en [1] : MD GROI en 168 | {0x2150, 0x03,}, 169 | // 170 | // 171 | // //--------------------------------------------------- 172 | // // frame rate : 5 FPS 173 | // //--------------------------------------------------- 174 | // W 24 0340 0C 2 1 ; smia frame length Hb 175 | {0x0340, 0x0C,}, 176 | // W 24 0341 7A 2 1 ; smia frame length Lb 3192 177 | {0x0341, 0x7A,}, 178 | // 179 | // W 24 0342 01 2 1 ; smia line length Hb 180 | {0x0342, 0x01,}, 181 | // W 24 0343 77 2 1 ; smia line length Lb 375 182 | {0x0343, 0x77,}, 183 | // 184 | // //--------------------------------------------------- 185 | // // Resolution : QVGA 324x244 186 | // //--------------------------------------------------- 187 | // W 24 3010 01 2 1 ; [0] : window mode 0 : full frame 324x324 1 : QVGA 188 | {0x3010, 0x01,}, 189 | // 190 | // 191 | // W 24 0383 01 2 1 ; 192 | {0x0383, 0x01,}, 193 | // W 24 0387 01 2 1 ; 194 | {0x0387, 0x01,}, 195 | // W 24 0390 00 2 1 ; 196 | {0x0390, 0x00,}, 197 | // 198 | // //--------------------------------------------------- 199 | // // bit width Selection 200 | // //--------------------------------------------------- 201 | // W 24 3011 70 2 1 ; [0] : 6 bit mode enable 202 | {0x3011, 0x70,}, 203 | // 204 | // 205 | // W 24 3059 02 2 1 ; [7]: Self OSC En, [6]: 4bit mode, [5]: serial mode, [4:0]: keep value as 0x02 206 | {0x3059, 0x02,}, 207 | // W 24 3060 01 2 1 ; [5]: gated_clock, [4]: msb first, 208 | {0x3060, 0x20,}, 209 | // ; [3:2]: vt_reg_div -> div by 4/8/1/2 210 | // ; [1;0]: vt_sys_div -> div by 8/4/2/1 211 | // 212 | // 213 | {0x0101, 0x01,}, 214 | // //--------------------------------------------------- 215 | // // CMU update 216 | // //--------------------------------------------------- 217 | // 218 | // W 24 0104 01 2 1 ; was 0100 219 | {0x0104, 0x01,}, 220 | // 221 | // 222 | // 223 | // //--------------------------------------------------- 224 | // // Turn on rolling shutter 225 | // //--------------------------------------------------- 226 | // W 24 0100 01 2 1 ; was 0005 ; mode_select 00 : standby - wait fir I2C SW trigger 01 : streaming 03 : output "N" frame, then enter standby 04 : standby - wait for HW trigger (level), then continuous video out til HW TRIG goes off 06 : standby - wait for HW trigger (edge), then output "N" frames then enter standby 227 | {0x0100, 0x00,}, 228 | // 229 | // ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 230 | }; -------------------------------------------------------------------------------- /src/hm01b0_walking1s_01.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _HM01B0_WALKING_1S_01_H_ 3 | #define _HM01B0_WALKING_1S_01_H_ 4 | 5 | #include "hm01b0.h" 6 | 7 | const hm_script_t sHM01b0TestModeScript_Walking1s[] = 8 | { 9 | {0x2100, 0x00,}, //W 24 2100 00 2 1 ; AE 10 | {0x1000, 0x00,}, //W 24 1000 00 2 1 ; BLC 11 | {0x1008, 0x00,}, //W 24 1008 00 2 1 ; DPC 12 | {0x0205, 0x00,}, //W 24 0205 00 2 1 ; AGain 13 | {0x020E, 0x01,}, //W 24 020E 01 2 1 ; DGain 14 | {0x020F, 0x00,}, //W 24 020F 00 2 1 ; DGain 15 | {0x0601, 0x11,}, //W 24 0601 11 2 1 ; Test pattern 16 | {0x0104, 0x01,}, //W 24 0104 01 2 1 ; 17 | }; 18 | 19 | #endif // _HM01B0_WALKING_1S_01_H_ 20 | -------------------------------------------------------------------------------- /src/platforms/README.md: -------------------------------------------------------------------------------- 1 | HM01B0 Platforms 2 | ================ 3 | 4 | Platforms allow for specialization of interface code for the camera module. There are two main domains for the interface: 5 | 6 | * Low-speed: Abstraction takes place with a virtual function table 7 | * High-speed: abstraction takes place with macros (preprocessor text replacement) 8 | 9 | A typical case will combine these files to implement a patform: 10 | * ```src/platforms/include/hm01b0_platform_{your_platform_name}.h``` : the 'platform header file' (included by ```src\hm01b0_c\src\hm01b0_c.c```) 11 | * ```src/platforms/src/hm01b0_platform_{your_platform_name}.cpp``` : the 'platform implementation file' (C++) 12 | * ```src/platforms/src/hm01b0_platform_{your_platform_name}.c``` : the 'platform implementation file' (C) 13 | 14 | Each platform must be gated by preprocessor defines that are unique to that architecture so as to avoid conflicts. For example: 15 | ** In platform implementation files (C/C++) ** 16 | ``` c 17 | #if defined (PLATFORM_UNIQUE_MACRO) 18 | ... 19 | ... // implementation code here 20 | ... 21 | #endif 22 | ``` 23 | 24 | ** In hm01b0_c.c ** 25 | ``` c 26 | ... 27 | ... // platform includes 28 | ... 29 | #elif defined (PLATFORM_UNIQUE_MACRO) 30 | #include "src/platforms/include/hm01b0_platform_{your_platform_name}.h" 31 | ... 32 | ... // more platform includes 33 | ... 34 | ``` 35 | 36 | ## Low-speed Interface 37 | The low-speed interface is used to handle I2C configuration, MCLK generation, and slow pin access like the trigger pin. 38 | 39 | The interface is abstracted through this construct: 40 | ``` c 41 | typedef hm01b0_status_e (*hm01b0_if_fn_t)(hm01b0_cfg_t* psCfg, void* arg); 42 | typedef hm01b0_status_e (*hm01b0_if_i2c_fn_t)(hm01b0_cfg_t* psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes, void* arg); 43 | typedef hm01b0_status_e (*hm01b0_if_on_off_fn_t)(hm01b0_cfg_t* psCfg, bool enable, void* arg); 44 | typedef struct { 45 | hm01b0_if_fn_t init; // any initialization code needed 46 | hm01b0_if_i2c_fn_t write; // write to registers over I2C 47 | hm01b0_if_i2c_fn_t read; // read from registers over I2C 48 | hm01b0_if_on_off_fn_t mclk; // enable/disable the clock generation hardware 49 | hm01b0_if_on_off_fn_t trig; // enable/disabe the trigger pin 50 | hm01b0_if_fn_t deinit; // any deinitialization code needed 51 | void* arg; // argument for the user available in interface functions 52 | } hm01b0_if_t; // abstracts the interface for the HM01B0 53 | ``` 54 | 55 | When porting a new platform create an ```hm01b0_if_t``` and fill it with pointers to appropriate functions. This structure is then referenced by the ```hm01b0_cfg_t``` structure called ```hm01b0_cfg``` which every platform must provide. 56 | 57 | 58 | 59 | 60 | ## High-speed Interface 61 | The high-speed interface is used in ```hm01b0_c.c``` to read data from the camera interface. You must implement the following macros: 62 | 63 | ``` c 64 | HM01B0_READ_VSYNC // (currently unused) 65 | HM01B0_READ_HSYNC // Evaluate to either 0 or 1 indicating the level of the HSYNC pin 66 | HM01B0_READ_PCLK // Evaluate to either 0 or 1 indicating the level of the PCLK pin 67 | HM01B0_READ_BYTE // Evaluate to an 8-bit quantity describing logic levels on data lines D0-7 68 | ``` 69 | 70 | These macros can be defined in the platform header file 71 | -------------------------------------------------------------------------------- /src/platforms/apollo3/include/hm01b0_platform_apollo3.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef _HM01B0_PLATFORM_APOLLO3_H_ 24 | #define _HM01B0_PLATFORM_APOLLO3_H_ 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include "am_mcu_apollo.h" 31 | #include "am_bsp.h" 32 | #include "am_util.h" 33 | 34 | #include "hm01b0.h" 35 | 36 | // Mapping BSP -> HM01B0 37 | #define HM01B0_PIN_D0 AM_BSP_GPIO_CAMERA_HM01B0_D0 38 | #define HM01B0_PIN_D1 AM_BSP_GPIO_CAMERA_HM01B0_D1 39 | #define HM01B0_PIN_D2 AM_BSP_GPIO_CAMERA_HM01B0_D2 40 | #define HM01B0_PIN_D3 AM_BSP_GPIO_CAMERA_HM01B0_D3 41 | #define HM01B0_PIN_D4 AM_BSP_GPIO_CAMERA_HM01B0_D4 42 | #define HM01B0_PIN_D5 AM_BSP_GPIO_CAMERA_HM01B0_D5 43 | #define HM01B0_PIN_D6 AM_BSP_GPIO_CAMERA_HM01B0_D6 44 | #define HM01B0_PIN_D7 AM_BSP_GPIO_CAMERA_HM01B0_D7 45 | #define HM01B0_PIN_VSYNC AM_BSP_GPIO_CAMERA_HM01B0_VSYNC 46 | #define HM01B0_PIN_HSYNC AM_BSP_GPIO_CAMERA_HM01B0_HSYNC 47 | #define HM01B0_PIN_PCLK AM_BSP_GPIO_CAMERA_HM01B0_PCLK 48 | #define HM01B0_PIN_SCL AM_BSP_CAMERA_HM01B0_I2C_SCL_PIN 49 | #define HM01B0_PIN_SDA AM_BSP_CAMERA_HM01B0_I2C_SDA_PIN 50 | 51 | // Some boards do not support TRIG or INT pins 52 | #ifdef AM_BSP_GPIO_CAMERA_HM01B0_TRIG 53 | #define HM01B0_PIN_TRIG AM_BSP_GPIO_CAMERA_HM01B0_TRIG 54 | #endif // AM_BSP_GPIO_CAMERA_HM01B0_TRIG 55 | 56 | #ifdef AM_BSP_GPIO_CAMERA_HM01B0_INT 57 | #define HM01B0_PIN_INT AM_BSP_GPIO_CAMERA_HM01B0_INT 58 | #endif // AM_BSP_GPIO_CAMERA_HM01B0_INT 59 | 60 | // Define AP3B's CTIMER and output pin for HM01B0 MCLK generation 61 | #define HM01B0_MCLK_GENERATOR_MOD AM_BSP_CAMERA_HM01B0_MCLK_GEN_MOD 62 | #define HM01B0_MCLK_GENERATOR_SEG AM_BSP_CAMERA_HM01B0_MCLK_GEN_SEG 63 | #define HM01B0_PIN_MCLK AM_BSP_CAMERA_HM01B0_MCLK_PIN 64 | 65 | // Deifne I2C controller and SCL(pin8)/SDA(pin9) are configured automatically. 66 | #define HM01B0_IOM_MODE AM_HAL_IOM_I2C_MODE 67 | #define HM01B0_IOM_MODULE AM_BSP_CAMERA_HM01B0_I2C_IOM 68 | #define HM01B0_I2C_CLOCK_FREQ AM_HAL_IOM_100KHZ 69 | 70 | // Fast-access macros 71 | #define HM01B0_READ_VSYNC (AM_REGVAL(AM_REGADDR(GPIO, RDA)) & (1 << HM01B0_PIN_VSYNC)) 72 | #define HM01B0_READ_HSYNC (AM_REGVAL(AM_REGADDR(GPIO, RDA)) & (1 << HM01B0_PIN_HSYNC)) 73 | #define HM01B0_READ_PCLK (AM_REGVAL(AM_REGADDR(GPIO, RDA)) & (1 << HM01B0_PIN_PCLK)) 74 | #define HM01B0_READ_BYTE (APBDMA->BBINPUT) 75 | 76 | 77 | // Type Definitions 78 | typedef struct _hm01b0_platform_apollo3_arg_t { 79 | uint16_t ui16SlvAddr; 80 | am_hal_iom_mode_e eIOMMode; 81 | uint32_t ui32IOMModule; 82 | am_hal_iom_config_t sIOMCfg; 83 | void *pIOMHandle; 84 | 85 | uint32_t ui32CTimerModule; 86 | uint32_t ui32CTimerSegment; 87 | uint32_t ui32CTimerOutputPin; 88 | 89 | uint8_t ui8PinSCL; 90 | uint8_t ui8PinSDA; 91 | uint8_t ui8PinD0; 92 | uint8_t ui8PinD1; 93 | uint8_t ui8PinD2; 94 | uint8_t ui8PinD3; 95 | uint8_t ui8PinD4; 96 | uint8_t ui8PinD5; 97 | uint8_t ui8PinD6; 98 | uint8_t ui8PinD7; 99 | uint8_t ui8PinVSYNC; 100 | uint8_t ui8PinHSYNC; 101 | uint8_t ui8PinPCLK; 102 | 103 | uint8_t ui8PinTrig; 104 | uint8_t ui8PinInt; 105 | void (*pfnGpioIsr)(void); 106 | } hm01b0_platform_apollo3_arg_t; 107 | extern hm01b0_platform_apollo3_arg_t hm01b0_platform_apollo3_args; 108 | 109 | // Apollo3 HM01B0 Configuration (provided to hm01b0_arduino.h) 110 | extern hm01b0_cfg_t hm01b0_cfg; 111 | 112 | // Interface Function Declarations 113 | hm01b0_status_e hm01b0_platform_apollo3_init(hm01b0_cfg_t* psCfg, void* arg); // any initialization code needed 114 | hm01b0_status_e hm01b0_platform_apollo3_write(hm01b0_cfg_t* psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes, void* arg); // write to registers over I2C 115 | hm01b0_status_e hm01b0_platform_apollo3_read(hm01b0_cfg_t* psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes, void* arg); // read from registers over I2C 116 | hm01b0_status_e hm01b0_platform_apollo3_mclk(hm01b0_cfg_t* psCfg, bool enable, void* arg); // enable/disable the clock generation hardware 117 | hm01b0_status_e hm01b0_platform_apollo3_trig(hm01b0_cfg_t* psCfg, bool enable, void* arg); // enable/disabe the trigger pin 118 | hm01b0_status_e hm01b0_platform_apollo3_deinit(hm01b0_cfg_t* psCfg, void* arg); // any deinitialization code needed 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | #endif // _HM01B0_PLATFORM_APOLLO3_H_ -------------------------------------------------------------------------------- /src/platforms/apollo3/src/hm01b0_platform_apollo3 .cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #if defined (ARDUINO_ARCH_APOLLO3) 24 | 25 | #include "platforms/apollo3/include/hm01b0_platform_apollo3.h" 26 | 27 | #endif // platform exclusion -------------------------------------------------------------------------------- /src/platforms/apollo3/src/hm01b0_platform_apollo3.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #if defined (ARDUINO_ARCH_APOLLO3) 24 | 25 | #include "platforms/apollo3/include/hm01b0_platform_apollo3.h" 26 | 27 | #define MCLK_UI64PATTERN 0x55555555 28 | #define MCLK_UI64PATTERNLEN 31 29 | 30 | // Forward Declarations 31 | hm01b0_status_e burst_mode_enable(bool bEnable); 32 | 33 | const am_hal_gpio_pincfg_t g_HM01B0_pin_int = 34 | { 35 | .uFuncSel = 3, 36 | .eGPOutcfg = AM_HAL_GPIO_PIN_OUTCFG_DISABLE, 37 | .eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI, 38 | .eGPInput = AM_HAL_GPIO_PIN_INPUT_ENABLE, 39 | .eGPRdZero = AM_HAL_GPIO_PIN_RDZERO_READPIN 40 | }; 41 | 42 | hm01b0_platform_apollo3_arg_t hm01b0_platform_apollo3_args = { 43 | // I2C settings 44 | .ui16SlvAddr = HM01B0_DEFAULT_ADDRESS, 45 | .eIOMMode = HM01B0_IOM_MODE, 46 | .ui32IOMModule = HM01B0_IOM_MODULE, 47 | .sIOMCfg = { 48 | .eInterfaceMode = HM01B0_IOM_MODE, 49 | .ui32ClockFreq = HM01B0_I2C_CLOCK_FREQ, 50 | }, 51 | .pIOMHandle = NULL, 52 | .ui8PinSCL = HM01B0_PIN_SCL, 53 | .ui8PinSDA = HM01B0_PIN_SDA, 54 | 55 | // MCLK settings 56 | .ui32CTimerModule = HM01B0_MCLK_GENERATOR_MOD, 57 | .ui32CTimerSegment = HM01B0_MCLK_GENERATOR_SEG, 58 | .ui32CTimerOutputPin = HM01B0_PIN_MCLK, 59 | 60 | // data interface 61 | .ui8PinD0 = HM01B0_PIN_D0, 62 | .ui8PinD1 = HM01B0_PIN_D1, 63 | .ui8PinD2 = HM01B0_PIN_D2, 64 | .ui8PinD3 = HM01B0_PIN_D3, 65 | .ui8PinD4 = HM01B0_PIN_D4, 66 | .ui8PinD5 = HM01B0_PIN_D5, 67 | .ui8PinD6 = HM01B0_PIN_D6, 68 | .ui8PinD7 = HM01B0_PIN_D7, 69 | .ui8PinVSYNC = HM01B0_PIN_VSYNC, 70 | .ui8PinHSYNC = HM01B0_PIN_HSYNC, 71 | .ui8PinPCLK = HM01B0_PIN_PCLK, 72 | 73 | #ifdef HM01B0_PIN_TRIG 74 | .ui8PinTrig = HM01B0_PIN_TRIG, 75 | #endif // HM01B0_PIN_TRIG 76 | 77 | #ifdef HM01B0_PIN_INT 78 | .ui8PinInt = HM01B0_PIN_INT, 79 | #endif // HM01B0_PIN_INT 80 | 81 | .pfnGpioIsr = NULL, 82 | }; 83 | 84 | // 85 | // Interface 86 | hm01b0_if_t hm01b0_platform_apollo3_if = { 87 | .init = hm01b0_platform_apollo3_init, 88 | .write = hm01b0_platform_apollo3_write, 89 | .read = hm01b0_platform_apollo3_read, 90 | .mclk = hm01b0_platform_apollo3_mclk, 91 | .trig = hm01b0_platform_apollo3_trig, 92 | .deinit = hm01b0_platform_apollo3_deinit, 93 | .arg = (void*)(&hm01b0_platform_apollo3_args), 94 | }; 95 | 96 | // 97 | // Apollo3 Configuration 98 | hm01b0_cfg_t hm01b0_cfg = { 99 | 100 | .interface = &hm01b0_platform_apollo3_if, 101 | }; 102 | 103 | 104 | 105 | // Interface Function Definitions 106 | hm01b0_status_e hm01b0_platform_apollo3_init(hm01b0_cfg_t* psCfg, void* arg){ 107 | hm01b0_status_e retval = HM01B0_ERR_OK; 108 | hm01b0_platform_apollo3_arg_t* args = (hm01b0_platform_apollo3_arg_t*)(arg); 109 | void *pIOMHandle = NULL; 110 | 111 | if ( args->ui32IOMModule > AM_REG_IOM_NUM_MODULES ){ 112 | return HM01B0_ERR_I2C; 113 | } 114 | 115 | // 116 | // Enable fault detection. 117 | #if AM_APOLLO3_MCUCTRL 118 | am_hal_mcuctrl_control(AM_HAL_MCUCTRL_CONTROL_FAULT_CAPTURE_ENABLE, 0); 119 | #else // AM_APOLLO3_MCUCTRL 120 | am_hal_mcuctrl_fault_capture_enable(); 121 | #endif // AM_APOLLO3_MCUCTRL 122 | 123 | // 124 | // Initialize the IOM instance. 125 | // Enable power to the IOM instance. 126 | // Configure the IOM for Serial operation during initialization. 127 | // Enable the IOM. 128 | // 129 | if (am_hal_iom_initialize(args->ui32IOMModule, &pIOMHandle) || am_hal_iom_power_ctrl(pIOMHandle, AM_HAL_SYSCTRL_WAKE, false) || am_hal_iom_configure(pIOMHandle, &(args->sIOMCfg)) || am_hal_iom_enable(pIOMHandle)){ 130 | return HM01B0_ERR_I2C; 131 | } 132 | else 133 | { 134 | // Configure the IOM pins. 135 | am_bsp_iom_pins_enable(args->ui32IOMModule, args->eIOMMode); 136 | args->pIOMHandle = pIOMHandle; 137 | } 138 | 139 | // initialize pins for camera parallel interface. 140 | am_hal_gpio_fastgpio_disable(args->ui8PinD0); 141 | am_hal_gpio_fastgpio_disable(args->ui8PinD1); 142 | am_hal_gpio_fastgpio_disable(args->ui8PinD2); 143 | am_hal_gpio_fastgpio_disable(args->ui8PinD3); 144 | am_hal_gpio_fastgpio_disable(args->ui8PinD4); 145 | am_hal_gpio_fastgpio_disable(args->ui8PinD5); 146 | am_hal_gpio_fastgpio_disable(args->ui8PinD6); 147 | am_hal_gpio_fastgpio_disable(args->ui8PinD7); 148 | 149 | am_hal_gpio_fastgpio_clr(args->ui8PinD0); 150 | am_hal_gpio_fastgpio_clr(args->ui8PinD1); 151 | am_hal_gpio_fastgpio_clr(args->ui8PinD2); 152 | am_hal_gpio_fastgpio_clr(args->ui8PinD3); 153 | am_hal_gpio_fastgpio_clr(args->ui8PinD4); 154 | am_hal_gpio_fastgpio_clr(args->ui8PinD5); 155 | am_hal_gpio_fastgpio_clr(args->ui8PinD6); 156 | am_hal_gpio_fastgpio_clr(args->ui8PinD7); 157 | 158 | am_hal_gpio_fast_pinconfig( (uint64_t)0x1 << args->ui8PinD0 | 159 | (uint64_t)0x1 << args->ui8PinD1 | 160 | (uint64_t)0x1 << args->ui8PinD2 | 161 | (uint64_t)0x1 << args->ui8PinD3 | 162 | (uint64_t)0x1 << args->ui8PinD4 | 163 | (uint64_t)0x1 << args->ui8PinD5 | 164 | (uint64_t)0x1 << args->ui8PinD6 | 165 | (uint64_t)0x1 << args->ui8PinD7, 166 | g_AM_HAL_GPIO_INPUT, 0); 167 | 168 | am_hal_gpio_pinconfig(args->ui8PinVSYNC, g_AM_HAL_GPIO_INPUT); 169 | am_hal_gpio_pinconfig(args->ui8PinHSYNC, g_AM_HAL_GPIO_INPUT); 170 | am_hal_gpio_pinconfig(args->ui8PinPCLK, g_AM_HAL_GPIO_INPUT); 171 | 172 | am_hal_gpio_pinconfig(args->ui8PinTrig, g_AM_HAL_GPIO_OUTPUT); 173 | 174 | am_hal_gpio_pinconfig(args->ui8PinInt, g_AM_HAL_GPIO_DISABLE); 175 | // am_hal_gpio_pinconfig(args->ui8PinInt, g_HM01B0_pin_int); 176 | // am_hal_gpio_interrupt_clear(AM_HAL_GPIO_BIT(args->ui8PinInt)); 177 | // am_hal_gpio_interrupt_enable(AM_HAL_GPIO_BIT(args->ui8PinInt)); 178 | // NVIC_EnableIRQ(GPIO_IRQn); 179 | 180 | retval |= burst_mode_enable(true); // turn on burst mode 181 | 182 | return retval; 183 | } 184 | 185 | hm01b0_status_e hm01b0_platform_apollo3_write(hm01b0_cfg_t* psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes, void* arg){ 186 | hm01b0_status_e retval = HM01B0_ERR_OK; 187 | am_hal_iom_transfer_t Transaction; 188 | hm01b0_platform_apollo3_arg_t* args = (hm01b0_platform_apollo3_arg_t*)(arg); 189 | 190 | // 191 | // Create the transaction. 192 | Transaction.ui32InstrLen = sizeof(uint16_t); 193 | Transaction.ui32Instr = (ui16Reg & 0x0000FFFF); 194 | Transaction.eDirection = AM_HAL_IOM_TX; 195 | Transaction.ui32NumBytes = ui32NumBytes; 196 | Transaction.pui32TxBuffer = (uint32_t *) pui8Value; 197 | Transaction.uPeerInfo.ui32I2CDevAddr = (uint32_t) args->ui16SlvAddr; 198 | Transaction.bContinue = false; 199 | Transaction.ui8RepeatCount = 0; 200 | Transaction.ui32PauseCondition = 0; 201 | Transaction.ui32StatusSetClr = 0; 202 | 203 | // 204 | // Execute the transction over IOM. 205 | if (am_hal_iom_blocking_transfer(args->pIOMHandle, &Transaction)) 206 | { 207 | return HM01B0_ERR_I2C; 208 | } 209 | return retval; 210 | } 211 | 212 | hm01b0_status_e hm01b0_platform_apollo3_read(hm01b0_cfg_t* psCfg, uint16_t ui16Reg, uint8_t *pui8Value, uint32_t ui32NumBytes, void* arg){ 213 | hm01b0_status_e retval = HM01B0_ERR_OK; 214 | am_hal_iom_transfer_t Transaction; 215 | hm01b0_platform_apollo3_arg_t* args = (hm01b0_platform_apollo3_arg_t*)(arg); 216 | 217 | // 218 | // Create the transaction. 219 | Transaction.ui32InstrLen = sizeof(uint16_t); 220 | Transaction.ui32Instr = (ui16Reg & 0x0000FFFF); 221 | Transaction.eDirection = AM_HAL_IOM_RX; 222 | Transaction.ui32NumBytes = ui32NumBytes; 223 | Transaction.pui32RxBuffer = (uint32_t *) pui8Value;; 224 | Transaction.uPeerInfo.ui32I2CDevAddr = (uint32_t) args->ui16SlvAddr; 225 | Transaction.bContinue = false; 226 | Transaction.ui8RepeatCount = 0; 227 | Transaction.ui32PauseCondition = 0; 228 | Transaction.ui32StatusSetClr = 0; 229 | 230 | // 231 | // Execute the transction over IOM. 232 | if (am_hal_iom_blocking_transfer(args->pIOMHandle, &Transaction)) 233 | { 234 | return HM01B0_ERR_I2C; 235 | } 236 | return retval; 237 | } 238 | 239 | hm01b0_status_e hm01b0_platform_apollo3_mclk(hm01b0_cfg_t* psCfg, bool enable, void* arg){ 240 | hm01b0_status_e retval = HM01B0_ERR_OK; 241 | hm01b0_platform_apollo3_arg_t* args = (hm01b0_platform_apollo3_arg_t*)(arg); 242 | static bool mclk_initialized = false; 243 | if(enable){ 244 | if(!mclk_initialized){ 245 | am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0); 246 | 247 | // Set up timer. 248 | am_hal_ctimer_clear(args->ui32CTimerModule, args->ui32CTimerSegment); 249 | am_hal_ctimer_config_single(args->ui32CTimerModule, args->ui32CTimerSegment, ( AM_HAL_CTIMER_FN_PTN_REPEAT | AM_HAL_CTIMER_HFRC_12MHZ )); 250 | 251 | // Set the pattern in the CMPR registers. 252 | am_hal_ctimer_compare_set(args->ui32CTimerModule, args->ui32CTimerSegment, 0, (uint32_t)(MCLK_UI64PATTERN & 0xFFFF)); 253 | am_hal_ctimer_compare_set(args->ui32CTimerModule, args->ui32CTimerSegment, 1, (uint32_t)((MCLK_UI64PATTERN >> 16) & 0xFFFF)); 254 | 255 | // Set the timer trigger and pattern length. 256 | am_hal_ctimer_config_trigger(args->ui32CTimerModule, args->ui32CTimerSegment, ( (MCLK_UI64PATTERNLEN << CTIMER_AUX0_TMRA0LMT_Pos) | (CTIMER_AUX0_TMRB0TRIG_DIS << CTIMER_AUX0_TMRA0TRIG_Pos))); 257 | 258 | // Configure timer output pin. 259 | am_hal_ctimer_output_config(args->ui32CTimerModule, args->ui32CTimerSegment, args->ui32CTimerOutputPin, AM_HAL_CTIMER_OUTPUT_NORMAL, AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA); 260 | 261 | // Start the timer. 262 | am_hal_ctimer_start(args->ui32CTimerModule, args->ui32CTimerSegment); 263 | } 264 | }else{ 265 | if(mclk_initialized){ 266 | // 267 | // Stop the timer. 268 | am_hal_ctimer_stop(args->ui32CTimerModule, args->ui32CTimerSegment); 269 | am_hal_gpio_pinconfig(args->ui32CTimerOutputPin, g_AM_HAL_GPIO_DISABLE); 270 | } 271 | } 272 | 273 | return retval; 274 | } 275 | 276 | hm01b0_status_e hm01b0_platform_apollo3_trig(hm01b0_cfg_t* psCfg, bool enable, void* arg){ 277 | hm01b0_status_e retval = HM01B0_ERR_OK; 278 | hm01b0_platform_apollo3_arg_t* args = (hm01b0_platform_apollo3_arg_t*)(arg); 279 | 280 | if(enable){ 281 | am_hal_gpio_output_set(args->ui8PinTrig); 282 | }else{ 283 | am_hal_gpio_output_clear(args->ui8PinTrig); 284 | } 285 | 286 | return retval; 287 | } 288 | 289 | hm01b0_status_e hm01b0_platform_apollo3_deinit(hm01b0_cfg_t* psCfg, void* arg){ 290 | hm01b0_status_e retval = HM01B0_ERR_OK; 291 | hm01b0_platform_apollo3_arg_t* args = (hm01b0_platform_apollo3_arg_t*)(arg); 292 | 293 | am_hal_iom_disable(args->pIOMHandle); 294 | am_hal_iom_uninitialize(args->pIOMHandle); 295 | 296 | am_hal_gpio_pinconfig(args->ui8PinSCL, g_AM_HAL_GPIO_DISABLE); 297 | am_hal_gpio_pinconfig(args->ui8PinSDA, g_AM_HAL_GPIO_DISABLE); 298 | 299 | // initialize pins for camera parallel interface. 300 | am_hal_gpio_fastgpio_disable(args->ui8PinD0); 301 | am_hal_gpio_fastgpio_disable(args->ui8PinD1); 302 | am_hal_gpio_fastgpio_disable(args->ui8PinD2); 303 | am_hal_gpio_fastgpio_disable(args->ui8PinD3); 304 | am_hal_gpio_fastgpio_disable(args->ui8PinD4); 305 | am_hal_gpio_fastgpio_disable(args->ui8PinD5); 306 | am_hal_gpio_fastgpio_disable(args->ui8PinD6); 307 | am_hal_gpio_fastgpio_disable(args->ui8PinD7); 308 | 309 | am_hal_gpio_fastgpio_clr(args->ui8PinD0); 310 | am_hal_gpio_fastgpio_clr(args->ui8PinD1); 311 | am_hal_gpio_fastgpio_clr(args->ui8PinD2); 312 | am_hal_gpio_fastgpio_clr(args->ui8PinD3); 313 | am_hal_gpio_fastgpio_clr(args->ui8PinD4); 314 | am_hal_gpio_fastgpio_clr(args->ui8PinD5); 315 | am_hal_gpio_fastgpio_clr(args->ui8PinD6); 316 | am_hal_gpio_fastgpio_clr(args->ui8PinD7); 317 | 318 | am_hal_gpio_pinconfig(args->ui8PinVSYNC, g_AM_HAL_GPIO_DISABLE); 319 | am_hal_gpio_pinconfig(args->ui8PinHSYNC, g_AM_HAL_GPIO_DISABLE); 320 | am_hal_gpio_pinconfig(args->ui8PinPCLK, g_AM_HAL_GPIO_DISABLE); 321 | am_hal_gpio_pinconfig(args->ui8PinTrig, g_AM_HAL_GPIO_DISABLE); 322 | am_hal_gpio_pinconfig(args->ui8PinInt, g_AM_HAL_GPIO_DISABLE); 323 | 324 | retval |= burst_mode_enable(false); // turn off burst mode 325 | 326 | return retval; 327 | } 328 | 329 | 330 | // burst mode enable 331 | hm01b0_status_e burst_mode_enable(bool bEnable){ 332 | am_hal_burst_avail_e eBurstModeAvailable; 333 | am_hal_burst_mode_e eBurstMode; 334 | 335 | // Check that the Burst Feature is available. 336 | if (AM_HAL_STATUS_SUCCESS == am_hal_burst_mode_initialize(&eBurstModeAvailable)){ 337 | if (AM_HAL_BURST_AVAIL == eBurstModeAvailable){ 338 | // am_util_stdio_printf("Apollo3 Burst Mode is Available\n"); 339 | } 340 | else{ 341 | // am_util_stdio_printf("Apollo3 Burst Mode is Not Available\n"); 342 | return HM01B0_ERR; 343 | } 344 | } 345 | else{ 346 | // am_util_stdio_printf("Failed to Initialize for Burst Mode operation\n"); 347 | return HM01B0_ERR; 348 | } 349 | 350 | // Put the MCU into "Burst" mode. 351 | if (bEnable) 352 | { 353 | if (AM_HAL_STATUS_SUCCESS == am_hal_burst_mode_enable(&eBurstMode)){ 354 | if (AM_HAL_BURST_MODE == eBurstMode){ 355 | // am_util_stdio_printf("Apollo3 operating in Burst Mode (96MHz)\n"); 356 | }else{ 357 | // am_util_stdio_printf("Failed to Enable Burst Mode operation\n"); 358 | return HM01B0_ERR; 359 | } 360 | } 361 | else{ 362 | // am_util_stdio_printf("Failed to Enable Burst Mode operation\n"); 363 | return HM01B0_ERR; 364 | } 365 | }else{ 366 | // Make sure we are in "Normal" mode. 367 | if (AM_HAL_STATUS_SUCCESS == am_hal_burst_mode_disable(&eBurstMode)){ 368 | if (AM_HAL_NORMAL_MODE == eBurstMode){ 369 | // am_util_stdio_printf("Apollo3 operating in Normal Mode (48MHz)\n"); 370 | }else{ 371 | // am_util_stdio_printf("Failed to Disable Burst Mode operation\n"); 372 | return HM01B0_ERR; 373 | } 374 | } 375 | else{ 376 | // am_util_stdio_printf("Failed to Disable Burst Mode operation\n"); 377 | return HM01B0_ERR; 378 | } 379 | } 380 | 381 | return HM01B0_ERR_OK; 382 | } 383 | 384 | 385 | #endif // platform exclusion -------------------------------------------------------------------------------- /src/platforms/arduino_generic/include/hm01b0_platform_arduino_generic.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 SparkFun Electronics 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef _HM01B0_PLATFORM_ARDUINO_GENERIC_C_H_ 24 | #define _HM01B0_PLATFORM_ARDUINO_GENERIC_C_H_ 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | #include "stdint.h" 31 | #include "hm01b0.h" 32 | 33 | // todo: implement real macros for generic Arduino imlementation 34 | #define HM01B0_READ_VSYNC (0) 35 | #define HM01B0_READ_HSYNC (0) 36 | #define HM01B0_READ_PCLK (0) 37 | #define HM01B0_READ_BYTE (0) 38 | 39 | // todo: implement an interface using generic Arduino functions 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif // _HM01B0_PLATFORM_ARDUINO_GENERIC_C_H_ -------------------------------------------------------------------------------- /utils/Example1_StopMotion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import sys 5 | import serial 6 | import serial.tools.list_ports as list_ports 7 | from time import sleep 8 | import argparse 9 | import os.path 10 | from array import * 11 | 12 | from PIL import Image 13 | import numpy as np 14 | import re 15 | 16 | dict_Resolutions = { 17 | 'QVGA': (324, 244), 18 | } 19 | 20 | # height = 244 21 | # width = 324 22 | 23 | VERSION = 0 24 | SUBVERSION = 1 25 | 26 | image_count = 0 27 | 28 | # class RawData: 29 | # ui8Array = None 30 | 31 | # def __init__(self): 32 | # self.ui8Array = array('B') 33 | 34 | 35 | # def check_file_existence(x): 36 | # if not os.path.isfile(x): 37 | # # Argparse uses the ArgumentTypeError to give a rejection message like: 38 | # # error: argument input: x does not exist 39 | # raise argparse.ArgumentTypeError("{0} does not exist".format(x)) 40 | # return x 41 | 42 | def map0(idx, iw, ih): 43 | return [int(idx%iw), int(idx/iw)] 44 | 45 | def map1(idx, iw, ih): 46 | return [int(idx/ih), ih-int(idx%ih)-1] 47 | 48 | def map2(idx, iw, ih): 49 | return [iw-int(idx%iw)-1, ih-int(idx/iw)-1] 50 | 51 | def map3(idx, iw, ih): 52 | return [iw-int(idx/ih)-1, int(idx%ih)] 53 | 54 | 55 | def create_bmp(args, rawdata): 56 | global image_count 57 | 58 | (width, height) = dict_Resolutions.get(args.resolution, ("Resolution not supported", 0, 0)) 59 | 60 | print("width: {}, height: {}".format(width, height)) 61 | 62 | if args.spin == 0: 63 | image_width = width 64 | map = map0 65 | elif args.spin == 1: 66 | image_width = height 67 | map = map1 68 | elif args.spin == 2: 69 | image_width = width 70 | map = map2 71 | else: 72 | image_width = height 73 | map = map3 74 | 75 | image_height = int((height*width)/image_width) 76 | print("iw: {}, ih: {}".format(image_width, image_height)) 77 | 78 | (um, vm) = map(width*height-1, image_width, image_height) 79 | print("um: {}, vm: {}".format(um, vm)) 80 | 81 | bitmap = np.zeros((image_width, image_height), dtype=np.uint8) 82 | 83 | # fill up bitmap array - always write u dimension first 84 | # (that's how data from the camera was streamed out) 85 | idx = 0 86 | for pixel in rawdata: 87 | (u, v) = map(idx, image_width, image_height) 88 | idx += 1 89 | bitmap[u, v] = pixel 90 | 91 | print(idx) 92 | 93 | path = os.path.dirname(args.outputfilepath) 94 | basename = 'hm01b0' 95 | outputfile = os.path.join(path, basename + '_' + str(image_count) + '.bmp') 96 | 97 | # print (bitmap) 98 | img = Image.fromarray(bitmap, 'L') 99 | img.save(outputfile) 100 | img.show() 101 | 102 | print ("%s created" % (basename + '_' + str(image_count) + '.bmp')) 103 | 104 | image_count += 1 105 | 106 | # *********************************************************************************** 107 | # 108 | # Help if serial port could not be opened 109 | # 110 | # *********************************************************************************** 111 | def phase_serial_port_help(args): 112 | devices = list_ports.comports() 113 | 114 | # First check to see if user has the given port open 115 | for dev in devices: 116 | if(dev.device.upper() == args.port.upper()): 117 | print(dev.device + " is currently open. Please close any other terminal programs that may be using " + 118 | dev.device + " and try again.") 119 | exit() 120 | 121 | # otherwise, give user a list of possible com ports 122 | print(args.port.upper() + 123 | " not found but we detected the following serial ports:") 124 | for dev in devices: 125 | if 'CH340' in dev.description: 126 | print( 127 | dev.description + ": Likely an Arduino or derivative. Try " + dev.device + ".") 128 | elif 'FTDI' in dev.description: 129 | print( 130 | dev.description + ": Likely an Arduino or derivative. Try " + dev.device + ".") 131 | elif 'USB Serial Device' in dev.description: 132 | print( 133 | dev.description + ": Possibly an Arduino or derivative.") 134 | else: 135 | print(dev.description) 136 | 137 | def sync(ser): 138 | synced = False 139 | restore_timeout = ser.timeout 140 | ser.timeout = 0.25 141 | count = 0 142 | while(not synced): 143 | result = ser.read_until(b'\x55') 144 | if(result != b''): 145 | print(result) 146 | if(result[len(result)-1] == 85): 147 | synced = True 148 | else: 149 | print(count) 150 | count += 1 151 | 152 | ser.timeout = restore_timeout 153 | 154 | 155 | def do_convert(args): 156 | 157 | (width, height) = dict_Resolutions.get(args.resolution, ("Resolution not supported", 0, 0)) 158 | 159 | try: 160 | 161 | with serial.Serial(args.port, args.baud) as ser: 162 | 163 | h_idx = 0 164 | w_idx = 0 165 | rawdata = None 166 | framestart = False 167 | framestop = False 168 | framelist = list() 169 | 170 | # collect all pixel data into an int array 171 | 172 | # handle startup byte-by-byte to avoid frustration 173 | 174 | print('waiting for first frame') 175 | ser.reset_input_buffer() 176 | sync(ser) 177 | 178 | print('ready') 179 | 180 | while(1): # todo: allow user to quit gracefully 181 | line = None 182 | try: 183 | line = ser.readline() 184 | line = line.decode('utf-8') 185 | # print(line, end='') 186 | except KeyboardInterrupt: 187 | exit() 188 | 189 | if line == "+++ frame +++\n": 190 | framestart = True 191 | rawdata = [] 192 | count = 0 193 | print(line, end='') 194 | print('start') 195 | continue 196 | elif line == '--- frame ---\n': 197 | framestop = True 198 | print(line, end='') 199 | # print(rawdata) 200 | 201 | # (address, length) = rawdata.buffer_info() 202 | 203 | # print(length) 204 | # print(rawdata.itemsize) 205 | 206 | if framestart == True and framestop == False: 207 | count += 1 208 | linelist = re.findall(r"[\w']+", line) 209 | 210 | if len(linelist) != 17: 211 | # drop this frame 212 | framestart = False 213 | continue 214 | 215 | for item in linelist[1 : ]: 216 | store = int(item, base=16) 217 | if(store > 255): 218 | store = 255 219 | rawdata.append(store) 220 | 221 | elif framestart == True and framestop == True: 222 | print('stop') 223 | print(count) 224 | print(len(rawdata)) 225 | 226 | create_bmp(args, rawdata) 227 | 228 | # (address, length) = rawdata.buffer_info() 229 | 230 | # if (length * rawdata.itemsize) != (height * width): 231 | # print ("Incorrect total data length {}, needs {}".format( length * rawdata.itemsize, height * width)) 232 | # else: 233 | # framelist.append(rawdata) 234 | 235 | framestart = False 236 | framestop = False 237 | 238 | except serial.SerialException: 239 | phase_serial_port_help(args) 240 | 241 | exit() 242 | 243 | def main(): 244 | parser = argparse.ArgumentParser( 245 | description = 'This program converts raw data from HM01B0 to bmp files from a serial connection.') 246 | 247 | parser.add_argument('-o', '--output', 248 | dest = 'outputfilepath', 249 | required = False, 250 | help = 'output file path', 251 | metavar = 'FILEPATH', 252 | default = '.', 253 | type = str 254 | ) 255 | 256 | parser.add_argument('-p', '--port', 257 | dest = 'port', 258 | required = True, 259 | help = 'serial port (COM*, /dev/tty*)', 260 | metavar = 'SERIAL_PORT', 261 | ) 262 | 263 | parser.add_argument('-b', '--baud', 264 | dest = 'baud', 265 | required = False, 266 | help = 'Baud rate that the board is configured for', 267 | type = int, 268 | default = 460800, 269 | ) 270 | 271 | parser.add_argument('-s', '--spin', 272 | dest = 'spin', 273 | required = False, 274 | help = 'A number 0-3 for how many times to rotate the image (90 degree increments)', 275 | type = int, 276 | default = 1, 277 | ) 278 | 279 | parser.add_argument('-r', '--resolution', 280 | dest = 'resolution', 281 | required = False, 282 | help = 'Resolution', 283 | choices = ['QVGA'], 284 | default = 'QVGA', 285 | ) 286 | 287 | parser.add_argument('-v', '--version', 288 | help = 'Program version', 289 | action = 'version', 290 | version = '%(prog)s {ver}'.format(ver = 'v%d.%d' %\ 291 | (VERSION, SUBVERSION)) 292 | ) 293 | 294 | args = parser.parse_args() 295 | 296 | do_convert(args) 297 | 298 | print ("done!") 299 | 300 | 301 | if __name__ == "__main__": 302 | main() -------------------------------------------------------------------------------- /utils/himax_script_convertor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import sys 5 | import argparse 6 | import os.path 7 | from array import * 8 | 9 | VERSION = 0 10 | SUBVERSION = 1 11 | 12 | HIMAX_CMD_OFFSET_OP = 0 13 | HIMAX_CMD_OFFSET_ADDR = 1 14 | HIMAX_CMD_OFFSET_REGADDR = 2 15 | HIMAX_CMD_OFFSET_REGVALUE = 3 16 | 17 | dict_DeviceDefaultAddress = { 18 | 'HM01B0': '24', 19 | } 20 | 21 | def check_file_existence(x): 22 | if not os.path.isfile(x): 23 | # Argparse uses the ArgumentTypeError to give a rejection message like: 24 | # error: argument input: x does not exist 25 | raise argparse.ArgumentTypeError("{0} does not exist".format(x)) 26 | return x 27 | 28 | def create_outputfile(args): 29 | 30 | path = os.path.dirname(os.path.abspath(args.ifile)) 31 | basename = os.path.split(os.path.splitext(args.ifile)[0])[-1] 32 | outputfile = os.path.join(path, basename + '.h') 33 | 34 | return outputfile 35 | 36 | def do_convert(args, ofilename): 37 | ofile = open(ofilename, 'w') 38 | ofile.write("\n") 39 | ofile.write("#include \"%s.h\"\n" % args.model) 40 | ofile.write("\n") 41 | ofile.write("const hm_script_t s%sInitScript[] =\n" % args.model) 42 | ofile.write("{\n") 43 | 44 | with open(args.ifile, 'r') as ifile: 45 | for line in ifile: 46 | items = line.split() 47 | ofile.write("// %s\n" % (' '.join(items))) 48 | print("// %s" % (' '.join(items))) 49 | if len(items) > 1: 50 | if items[HIMAX_CMD_OFFSET_OP] == 'W' and items[HIMAX_CMD_OFFSET_ADDR] == dict_DeviceDefaultAddress.get(args.model): 51 | print(" {0x%s, 0x%s,}," % (items[HIMAX_CMD_OFFSET_REGADDR], items[HIMAX_CMD_OFFSET_REGVALUE])) 52 | ofile.write(" {0x%s, 0x%s,},\n" % (items[HIMAX_CMD_OFFSET_REGADDR], items[HIMAX_CMD_OFFSET_REGVALUE])) 53 | 54 | ofile.write("};\n") 55 | ofile.close() 56 | 57 | def main(): 58 | parser = argparse.ArgumentParser( 59 | description = 'This program converts a given Himax Script into a c header file.') 60 | 61 | parser.add_argument('-i', '--input', 62 | dest = 'ifile', 63 | required = True, 64 | help = 'input file', 65 | metavar = 'FILE', 66 | type = check_file_existence) 67 | 68 | parser.add_argument('-m', '--model', 69 | dest = 'model', 70 | required = True, 71 | help = 'Himax Sensor Model', 72 | choices = ['HM01B0'], 73 | default = 'HM01B0', 74 | ) 75 | 76 | 77 | parser.add_argument('-v', '--version', 78 | help = 'show the program version', 79 | action = 'version', 80 | version = '%(prog)s {ver}'.format(ver = 'v%d.%d' %\ 81 | (VERSION, SUBVERSION))) 82 | 83 | args = parser.parse_args() 84 | 85 | ofilename = create_outputfile(args) 86 | 87 | # print('%s' % ofile) 88 | 89 | do_convert(args, ofilename) 90 | 91 | print "done!" 92 | 93 | 94 | if __name__ == "__main__": 95 | main() -------------------------------------------------------------------------------- /utils/raw2bmp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import os 4 | import sys 5 | import argparse 6 | import os.path 7 | from array import * 8 | 9 | from PIL import Image 10 | import numpy as np 11 | import re 12 | 13 | dict_Resolutions = { 14 | 'QVGA': (324, 244), 15 | } 16 | 17 | # height = 244 18 | # width = 324 19 | 20 | VERSION = 0 21 | SUBVERSION = 1 22 | 23 | class RawData: 24 | ui8Array = None 25 | 26 | def __init__(self): 27 | self.ui8Array = array('B') 28 | 29 | 30 | def check_file_existence(x): 31 | if not os.path.isfile(x): 32 | # Argparse uses the ArgumentTypeError to give a rejection message like: 33 | # error: argument input: x does not exist 34 | raise argparse.ArgumentTypeError("{0} does not exist".format(x)) 35 | return x 36 | 37 | def create_bmp(args, framelist): 38 | 39 | (width, height) = dict_Resolutions.get(args.resolution, ("Resolution not supported", 0, 0)) 40 | 41 | for idx, frame in enumerate(framelist): 42 | bitmap = np.zeros((height, width), dtype=np.uint8) 43 | 44 | h_idx = height - 1 45 | w_idx = 0 46 | 47 | # fill up bitmap array 48 | for pixel in frame.ui8Array: 49 | bitmap[h_idx, w_idx] = pixel 50 | if w_idx == width - 1: 51 | w_idx = 0 52 | h_idx -= 1 53 | else: 54 | w_idx += 1 55 | 56 | 57 | 58 | # h_idx = height - 1 59 | # w_idx = width - 1 60 | 61 | # # fill up bitmap array 62 | # for pixel in frame.ui8Array: 63 | # bitmap[h_idx, w_idx] = pixel 64 | # if w_idx == 0: 65 | # w_idx = width - 1 66 | # h_idx -= 1 67 | # else: 68 | # w_idx -= 1 69 | 70 | 71 | 72 | # h_idx = 0 73 | # w_idx = 0 74 | 75 | # # fill up bitmap array 76 | # for pixel in frame.ui8Array: 77 | # bitmap[h_idx, w_idx] = pixel 78 | # if w_idx == width - 1: 79 | # w_idx = 0 80 | # h_idx += 1 81 | # else: 82 | # w_idx += 1 83 | 84 | 85 | 86 | path = os.path.dirname(os.path.abspath(args.inputfile)) 87 | basename = os.path.split(os.path.splitext(args.inputfile)[0])[-1] 88 | outputfile = os.path.join(path, basename + '_' + str(idx) + '.bmp') 89 | 90 | # print (bitmap) 91 | img = Image.fromarray(bitmap, 'L') 92 | img.save(outputfile) 93 | img.show() 94 | 95 | print ("%s created" % (basename + '_' + str(idx) + '.bmp')) 96 | 97 | def do_convert(args): 98 | 99 | (width, height) = dict_Resolutions.get(args.resolution, ("Resolution not supported", 0, 0)) 100 | 101 | with open(args.inputfile) as f: 102 | h_idx = 0 103 | w_idx = 0 104 | rawdata = None 105 | framestart = False 106 | framestop = False 107 | framelist = list() 108 | 109 | # collect all pixel data into an int array 110 | for line in f: 111 | if line == "+++ frame +++\n": 112 | framestart = True 113 | rawdata = RawData() 114 | continue 115 | elif line == '--- frame ---\n': 116 | framestop = True 117 | 118 | if framestart == True and framestop == False: 119 | linelist = re.findall(r"[\w']+", line) 120 | 121 | if len(linelist) != 17: 122 | # drop this frame 123 | framestart = False 124 | continue 125 | 126 | for item in linelist[1 : ]: 127 | rawdata.ui8Array.append(int(item, base=16)) 128 | 129 | elif framestart == True and framestop == True: 130 | 131 | (address, length) = rawdata.ui8Array.buffer_info() 132 | 133 | if (length * rawdata.ui8Array.itemsize) != (height * width): 134 | print ("Incorrect total data length %d" % length * rawdata.ui8Array.itemsize) 135 | else: 136 | framelist.append(rawdata) 137 | framestart = False 138 | framestop = False 139 | 140 | create_bmp(args, framelist) 141 | 142 | def main(): 143 | parser = argparse.ArgumentParser( 144 | description = 'This program converts raw data from HM01B0 to a bmp file.') 145 | 146 | parser.add_argument('-i', '--input', 147 | dest = 'inputfile', 148 | required = True, 149 | help = 'input file', 150 | metavar = 'FILE', 151 | type = check_file_existence 152 | ) 153 | 154 | parser.add_argument('-r', '--resolution', 155 | dest = 'resolution', 156 | required = False, 157 | help = 'Resolution', 158 | choices = ['QVGA'], 159 | default = 'QVGA', 160 | ) 161 | 162 | parser.add_argument('-v', '--version', 163 | help = 'Program version', 164 | action = 'version', 165 | version = '%(prog)s {ver}'.format(ver = 'v%d.%d' %\ 166 | (VERSION, SUBVERSION)) 167 | ) 168 | 169 | args = parser.parse_args() 170 | 171 | do_convert(args) 172 | 173 | print ("done!") 174 | 175 | 176 | if __name__ == "__main__": 177 | main() --------------------------------------------------------------------------------