#include #include "pico/stdlib.h" #include "arducam.h" #include "ov2640_init.h" #include "hm01b0_init.h" #include "hardware/dma.h" #include "hardware/i2c.h" #include "hardware/pwm.h" #include "image.pio.h" int PIN_LED = 25; int PIN_CAM_SIOC = 5; // I2C0 SCL int PIN_CAM_SIOD = 4; // I2C0 SDA int PIN_CAM_RESETB = 2; int PIN_CAM_XCLK = 3; int PIN_CAM_VSYNC = 16; //GP15 hsync GP14 pixel clock int PIN_CAM_Y2_PIO_BASE = 6; // data GPIO6 #if defined (SOFTWARE_I2C) #define SCCB_SIC_H() gpio_put(PIN_CAM_SIOC,1) //SCL H #define SCCB_SIC_L() gpio_put(PIN_CAM_SIOC,0) //SCL H #define SCCB_SID_H() gpio_put(PIN_CAM_SIOD,1) //SDA H #define SCCB_SID_L() gpio_put(PIN_CAM_SIOD,0) //SDA H #define SCCB_DATA_IN gpio_set_dir(PIN_CAM_SIOD, GPIO_IN); #define SCCB_DATA_OUT gpio_set_dir(PIN_CAM_SIOD, GPIO_OUT); #define SCCB_SID_STATE gpio_get(PIN_CAM_SIOD) void sccb_bus_init(void); void sccb_bus_start(void); void sccb_bus_stop(void); void sccb_bus_send_noack(void); void sccb_bus_send_ack(void); unsigned char sccb_bus_write_byte(unsigned char data); unsigned char sccb_bus_read_byte(void); unsigned char I2C_TIM; void sccb_bus_start(void) { SCCB_SID_H(); sleep_us(I2C_TIM); SCCB_SIC_H(); sleep_us(I2C_TIM); SCCB_SID_L(); sleep_us(I2C_TIM); SCCB_SIC_L(); sleep_us(I2C_TIM); } void sccb_bus_stop(void) { SCCB_SID_L(); sleep_us(I2C_TIM); SCCB_SIC_H(); sleep_us(I2C_TIM); SCCB_SID_H(); sleep_us(I2C_TIM); } void sccb_bus_send_noack(void) { SCCB_SID_H(); sleep_us(I2C_TIM); SCCB_SIC_H(); sleep_us(I2C_TIM); SCCB_SIC_L(); sleep_us(I2C_TIM); SCCB_SID_L(); sleep_us(I2C_TIM); } void sccb_bus_send_ack(void) { SCCB_SID_L(); sleep_us(I2C_TIM); SCCB_SIC_L(); sleep_us(I2C_TIM); SCCB_SIC_H(); sleep_us(I2C_TIM); SCCB_SIC_L(); sleep_us(I2C_TIM); SCCB_SID_L(); sleep_us(I2C_TIM); } unsigned char sccb_bus_write_byte(unsigned char data) { unsigned char i; unsigned char tem; for(i = 0; i < 8; i++) { if((data< 0; i--) { sleep_us(I2C_TIM); SCCB_SIC_H(); sleep_us(I2C_TIM); read = read << 1; if(SCCB_SID_STATE) { read += 1; } SCCB_SIC_L(); sleep_us(I2C_TIM); } SCCB_DATA_OUT; return read; } unsigned char wrSensorReg16_8( uint8_t slave_address, int regID, int regDat) { sccb_bus_start(); if(0==sccb_bus_write_byte(slave_address<<1)) { sccb_bus_stop(); return(0); } sleep_us(10); if(0==sccb_bus_write_byte(regID>>8)) { sccb_bus_stop(); return(0); } sleep_us(10); if(0==sccb_bus_write_byte(regID)) { sccb_bus_stop(); return(0); } sleep_us(10); if(0==sccb_bus_write_byte(regDat)) { sccb_bus_stop(); return(0); } sccb_bus_stop(); return(1); } unsigned char rdSensorReg16_8(uint8_t slave_address, unsigned int regID, unsigned char* regDat) { sccb_bus_start(); if(0==sccb_bus_write_byte(slave_address<<1)) { sccb_bus_stop(); return(0); } sleep_us(20); sleep_us(20); if(0==sccb_bus_write_byte(regID>>8)) { sccb_bus_stop(); return(0); } sleep_us(20); if(0==sccb_bus_write_byte(regID)) { sccb_bus_stop(); return(0); } sleep_us(20); sccb_bus_stop(); sleep_us(20); sccb_bus_start(); if(0==sccb_bus_write_byte((slave_address<<1)|0x01)) { sccb_bus_stop(); return(0); } sleep_us(20); *regDat=sccb_bus_read_byte(); sccb_bus_send_noack(); sccb_bus_stop(); return(1); } #endif void arducam_init(struct arducam_config *config){ gpio_set_function(config->pin_xclk, GPIO_FUNC_PWM); uint slice_num = pwm_gpio_to_slice_num(config->pin_xclk); // 6 cycles (0 to 5), 125 MHz / 6 = ~20.83 MHz wrap rate pwm_set_wrap(slice_num, 9); pwm_set_gpio_level(config->pin_xclk, 3); pwm_set_enabled(slice_num, true); #ifndef SOFTWARE_I2C // SCCB I2C @ 100 kHz gpio_set_function(config->pin_sioc, GPIO_FUNC_I2C); gpio_set_function(config->pin_siod, GPIO_FUNC_I2C); i2c_init(config->sccb, 100 * 1000); #else gpio_init(config->pin_sioc); gpio_init(config->pin_siod); gpio_set_dir(config->pin_sioc, GPIO_OUT); gpio_set_dir(config->pin_siod, GPIO_OUT); #endif // Initialise reset pin gpio_init(config->pin_resetb); gpio_set_dir(config->pin_resetb, GPIO_OUT); // Reset camera, and give it some time to wake back up gpio_put(config->pin_resetb, 0); sleep_ms(100); gpio_put(config->pin_resetb, 1); sleep_ms(100); // Initialise the camera itself over SCCB arducam_regs_write(config, hm01b0_324x244); // Enable image RX PIO uint offset = pio_add_program(config->pio, &image_program); image_program_init(config->pio, config->pio_sm, offset, config->pin_y2_pio_base); } void arducam_capture_frame(struct arducam_config *config) { dma_channel_config c = dma_channel_get_default_config(config->dma_channel); channel_config_set_read_increment(&c, false); channel_config_set_write_increment(&c, true); channel_config_set_dreq(&c, pio_get_dreq(config->pio, config->pio_sm, false)); channel_config_set_transfer_data_size(&c, DMA_SIZE_8); dma_channel_configure( config->dma_channel, &c, config->image_buf, &config->pio->rxf[config->pio_sm], config->image_buf_size, false ); // Wait for vsync rising edge to start frame while (gpio_get(config->pin_vsync) == true); while (gpio_get(config->pin_vsync) == false); dma_channel_start(config->dma_channel); pio_sm_set_enabled(config->pio, config->pio_sm, true); dma_channel_wait_for_finish_blocking(config->dma_channel); pio_sm_set_enabled(config->pio, config->pio_sm, false); } void arducam_reg_write(struct arducam_config *config, uint16_t reg, uint8_t value) { uint8_t data[3]; uint8_t length =0; switch (config->sccb_mode){ case I2C_MODE_16_8: data[0] = (uint8_t)(reg>>8)&0xFF; data[1] = (uint8_t)(reg)&0xFF; data[2] = value; length = 3; break; case I2C_MODE_8_8: data[0] = (uint8_t)(reg)&0xFF; data[1] = value; length = 2; break; } //printf("length: %x data[0]: = %x data[1] = %x data[2] = %x\r\n", length, data[0],data[1],data[2]); #ifndef SOFTWARE_I2C int ret = i2c_write_blocking(config->sccb, config->sensor_address, data, length, false); #else int ret = wrSensorReg16_8(config->sensor_address, reg, value); #endif //printf("ret: %x\r\n", ret); } uint8_t arducam_reg_read(struct arducam_config *config, uint16_t reg) { uint8_t data[2]; uint8_t length; switch (config->sccb_mode){ case I2C_MODE_16_8: data[0] = (uint8_t)(reg>>8)&0xFF; data[1] = (uint8_t)(reg)&0xFF; length = 2; case I2C_MODE_8_8: data[0] = (uint8_t)reg&0xFF; length = 1; } i2c_write_blocking(config->sccb, config->sensor_address, data, length, false); uint8_t value; i2c_read_blocking(config->sccb, config->sensor_address, &value, 1, false); return value; } void arducam_regs_write(struct arducam_config *config, struct senosr_reg* regs_list) { while (1) { uint16_t reg = regs_list->reg; uint8_t value = regs_list->val; if (reg == 0xFFFF && value == 0xFF) { break; } //printf("reg: 0x%04x , val: 0x%02x\r\n",reg, value); arducam_reg_write(config, reg, value); regs_list++; } }