mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-09 04:56:53 +03:00
Initial Code v0.1.0
This commit is contained in:
1520
code/lib/driver/camera.c
Normal file
1520
code/lib/driver/camera.c
Normal file
File diff suppressed because it is too large
Load Diff
49
code/lib/driver/camera_common.h
Normal file
49
code/lib/driver/camera_common.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_camera.h"
|
||||
#include "sensor.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/rom/lldesc.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/lldesc.h"
|
||||
#endif
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t sample2;
|
||||
uint8_t unused2;
|
||||
uint8_t sample1;
|
||||
uint8_t unused1;
|
||||
};
|
||||
uint32_t val;
|
||||
} dma_elem_t;
|
||||
|
||||
typedef enum {
|
||||
/* camera sends byte sequence: s1, s2, s3, s4, ...
|
||||
* fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ...
|
||||
*/
|
||||
SM_0A0B_0B0C = 0,
|
||||
/* camera sends byte sequence: s1, s2, s3, s4, ...
|
||||
* fifo receives: 00 s1 00 s2, 00 s3 00 s4, ...
|
||||
*/
|
||||
SM_0A0B_0C0D = 1,
|
||||
/* camera sends byte sequence: s1, s2, s3, s4, ...
|
||||
* fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ...
|
||||
*/
|
||||
SM_0A00_0B00 = 3,
|
||||
} i2s_sampling_mode_t;
|
||||
|
||||
200
code/lib/driver/esp_camera.h
Normal file
200
code/lib/driver/esp_camera.h
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* Example Use
|
||||
*
|
||||
static camera_config_t camera_example_config = {
|
||||
.pin_pwdn = PIN_PWDN,
|
||||
.pin_reset = PIN_RESET,
|
||||
.pin_xclk = PIN_XCLK,
|
||||
.pin_sscb_sda = PIN_SIOD,
|
||||
.pin_sscb_scl = PIN_SIOC,
|
||||
.pin_d7 = PIN_D7,
|
||||
.pin_d6 = PIN_D6,
|
||||
.pin_d5 = PIN_D5,
|
||||
.pin_d4 = PIN_D4,
|
||||
.pin_d3 = PIN_D3,
|
||||
.pin_d2 = PIN_D2,
|
||||
.pin_d1 = PIN_D1,
|
||||
.pin_d0 = PIN_D0,
|
||||
.pin_vsync = PIN_VSYNC,
|
||||
.pin_href = PIN_HREF,
|
||||
.pin_pclk = PIN_PCLK,
|
||||
|
||||
.xclk_freq_hz = 20000000,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
.pixel_format = PIXFORMAT_JPEG,
|
||||
.frame_size = FRAMESIZE_SVGA,
|
||||
.jpeg_quality = 10,
|
||||
.fb_count = 2
|
||||
};
|
||||
|
||||
esp_err_t camera_example_init(){
|
||||
return esp_camera_init(&camera_example_config);
|
||||
}
|
||||
|
||||
esp_err_t camera_example_capture(){
|
||||
//capture a frame
|
||||
camera_fb_t * fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
ESP_LOGE(TAG, "Frame buffer could not be acquired");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
//replace this with your own function
|
||||
display_image(fb->width, fb->height, fb->pixformat, fb->buf, fb->len);
|
||||
|
||||
//return the frame buffer back to be reused
|
||||
esp_camera_fb_return(fb);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef ESPCAMERADEF
|
||||
#define ESPCAMERADEF
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "sensor.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for camera initialization
|
||||
*/
|
||||
typedef struct {
|
||||
int pin_pwdn; /*!< GPIO pin for camera power down line */
|
||||
int pin_reset; /*!< GPIO pin for camera reset line */
|
||||
int pin_xclk; /*!< GPIO pin for camera XCLK line */
|
||||
int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
|
||||
int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
|
||||
int pin_d7; /*!< GPIO pin for camera D7 line */
|
||||
int pin_d6; /*!< GPIO pin for camera D6 line */
|
||||
int pin_d5; /*!< GPIO pin for camera D5 line */
|
||||
int pin_d4; /*!< GPIO pin for camera D4 line */
|
||||
int pin_d3; /*!< GPIO pin for camera D3 line */
|
||||
int pin_d2; /*!< GPIO pin for camera D2 line */
|
||||
int pin_d1; /*!< GPIO pin for camera D1 line */
|
||||
int pin_d0; /*!< GPIO pin for camera D0 line */
|
||||
int pin_vsync; /*!< GPIO pin for camera VSYNC line */
|
||||
int pin_href; /*!< GPIO pin for camera HREF line */
|
||||
int pin_pclk; /*!< GPIO pin for camera PCLK line */
|
||||
|
||||
int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. Either 20KHz or 10KHz for OV2640 double FPS (Experimental) */
|
||||
|
||||
ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */
|
||||
ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */
|
||||
|
||||
pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */
|
||||
framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */
|
||||
|
||||
int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */
|
||||
size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */
|
||||
} camera_config_t;
|
||||
|
||||
/**
|
||||
* @brief Data structure of camera frame buffer
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t * buf; /*!< Pointer to the pixel data */
|
||||
size_t len; /*!< Length of the buffer in bytes */
|
||||
size_t width; /*!< Width of the buffer in pixels */
|
||||
size_t height; /*!< Height of the buffer in pixels */
|
||||
pixformat_t format; /*!< Format of the pixel data */
|
||||
struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */
|
||||
} camera_fb_t;
|
||||
|
||||
#define ESP_ERR_CAMERA_BASE 0x20000
|
||||
#define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1)
|
||||
#define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2)
|
||||
#define ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT (ESP_ERR_CAMERA_BASE + 3)
|
||||
#define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 4)
|
||||
|
||||
/**
|
||||
* @brief Initialize the camera driver
|
||||
*
|
||||
* @note call camera_probe before calling this function
|
||||
*
|
||||
* This function detects and configures camera over I2C interface,
|
||||
* allocates framebuffer and DMA buffers,
|
||||
* initializes parallel I2S input, and sets up DMA descriptors.
|
||||
*
|
||||
* Currently this function can only be called once and there is
|
||||
* no way to de-initialize this module.
|
||||
*
|
||||
* @param config Camera configuration parameters
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_camera_init(const camera_config_t* config);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the camera driver
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet
|
||||
*/
|
||||
esp_err_t esp_camera_deinit();
|
||||
|
||||
/**
|
||||
* @brief Obtain pointer to a frame buffer.
|
||||
*
|
||||
* @return pointer to the frame buffer
|
||||
*/
|
||||
camera_fb_t* esp_camera_fb_get();
|
||||
|
||||
/**
|
||||
* @brief Return the frame buffer to be reused again.
|
||||
*
|
||||
* @param fb Pointer to the frame buffer
|
||||
*/
|
||||
void esp_camera_fb_return(camera_fb_t * fb);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the image sensor control structure
|
||||
*
|
||||
* @return pointer to the sensor
|
||||
*/
|
||||
sensor_t * esp_camera_sensor_get();
|
||||
|
||||
/**
|
||||
* @brief Save camera settings to non-volatile-storage (NVS)
|
||||
*
|
||||
* @param key A unique nvs key name for the camera settings
|
||||
*/
|
||||
esp_err_t esp_camera_save_to_nvs(const char *key);
|
||||
|
||||
/**
|
||||
* @brief Load camera settings from non-volatile-storage (NVS)
|
||||
*
|
||||
* @param key A unique nvs key name for the camera settings
|
||||
*/
|
||||
esp_err_t esp_camera_load_from_nvs(const char *key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "img_converters.h"
|
||||
|
||||
#endif
|
||||
|
||||
260
code/lib/driver/sccb.c
Normal file
260
code/lib/driver/sccb.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* SCCB (I2C like) driver.
|
||||
*
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "sccb.h"
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "sccb";
|
||||
#endif
|
||||
|
||||
//#undef CONFIG_SCCB_HARDWARE_I2C
|
||||
|
||||
#define LITTLETOBIG(x) ((x<<8)|(x>>8))
|
||||
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
#include "driver/i2c.h"
|
||||
|
||||
#define SCCB_FREQ 100000 /*!< I2C master frequency*/
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||||
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
#if CONFIG_SCCB_HARDWARE_I2C_PORT1
|
||||
const int SCCB_I2C_PORT = 1;
|
||||
#else
|
||||
const int SCCB_I2C_PORT = 0;
|
||||
#endif
|
||||
static uint8_t ESP_SLAVE_ADDR = 0x3c;
|
||||
#else
|
||||
#include "twi.h"
|
||||
#endif
|
||||
|
||||
int SCCB_Init(int pin_sda, int pin_scl)
|
||||
{
|
||||
ESP_LOGI(TAG, "pin_sda %d pin_scl %d\n", pin_sda, pin_scl);
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
//log_i("SCCB_Init start");
|
||||
i2c_config_t conf;
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = pin_sda;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.scl_io_num = pin_scl;
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = SCCB_FREQ;
|
||||
|
||||
i2c_param_config(SCCB_I2C_PORT, &conf);
|
||||
i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
|
||||
#else
|
||||
twi_init(pin_sda, pin_scl);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t SCCB_Probe()
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
uint8_t slave_addr = 0x0;
|
||||
while(slave_addr < 0x7f) {
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if( ret == ESP_OK) {
|
||||
ESP_SLAVE_ADDR = slave_addr;
|
||||
return ESP_SLAVE_ADDR;
|
||||
}
|
||||
slave_addr++;
|
||||
}
|
||||
return ESP_SLAVE_ADDR;
|
||||
#else
|
||||
uint8_t reg = 0x00;
|
||||
uint8_t slv_addr = 0x00;
|
||||
|
||||
ESP_LOGI(TAG, "SCCB_Probe start");
|
||||
for (uint8_t i = 0; i < 127; i++) {
|
||||
if (twi_writeTo(i, ®, 1, true) == 0) {
|
||||
slv_addr = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i!=126) {
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); // Necessary for OV7725 camera (not for OV2640).
|
||||
}
|
||||
}
|
||||
return slv_addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
uint8_t data=0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
}
|
||||
return data;
|
||||
#else
|
||||
uint8_t data=0;
|
||||
|
||||
int rc = twi_writeTo(slv_addr, ®, 1, true);
|
||||
if (rc != 0) {
|
||||
data = 0xff;
|
||||
} else {
|
||||
rc = twi_readFrom(slv_addr, &data, 1, true);
|
||||
if (rc != 0) {
|
||||
data=0xFF;
|
||||
}
|
||||
}
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "SCCB_Read [%02x] failed rc=%d\n", reg, rc);
|
||||
}
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
}
|
||||
return ret == ESP_OK ? 0 : -1;
|
||||
#else
|
||||
uint8_t ret=0;
|
||||
uint8_t buf[] = {reg, data};
|
||||
|
||||
if(twi_writeTo(slv_addr, buf, 2, true) != 0) {
|
||||
ret=0xFF;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "SCCB_Write [%02x]=%02x failed\n", reg, data);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
{
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
uint8_t data=0;
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
|
||||
}
|
||||
return data;
|
||||
#else
|
||||
uint8_t data=0;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
uint8_t buf[] = {reg_u8[0], reg_u8[1]};
|
||||
|
||||
int rc = twi_writeTo(slv_addr, buf, 2, true);
|
||||
if (rc != 0) {
|
||||
data = 0xff;
|
||||
} else {
|
||||
rc = twi_readFrom(slv_addr, &data, 1, true);
|
||||
if (rc != 0) {
|
||||
data=0xFF;
|
||||
}
|
||||
}
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "R [%04x] fail rc=%d\n", reg, rc);
|
||||
}
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data)
|
||||
{
|
||||
static uint16_t i = 0;
|
||||
#ifdef CONFIG_SCCB_HARDWARE_I2C
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
}
|
||||
return ret == ESP_OK ? 0 : -1;
|
||||
#else
|
||||
uint8_t ret=0;
|
||||
uint16_t reg_htons = LITTLETOBIG(reg);
|
||||
uint8_t *reg_u8 = (uint8_t *)®_htons;
|
||||
uint8_t buf[] = {reg_u8[0], reg_u8[1], data};
|
||||
|
||||
if(twi_writeTo(slv_addr, buf, 3, true) != 0) {
|
||||
ret = 0xFF;
|
||||
}
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
18
code/lib/driver/sccb.h
Normal file
18
code/lib/driver/sccb.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* SCCB (I2C like) driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __SCCB_H__
|
||||
#define __SCCB_H__
|
||||
#include <stdint.h>
|
||||
int SCCB_Init(int pin_sda, int pin_scl);
|
||||
uint8_t SCCB_Probe();
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
||||
uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data);
|
||||
uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg);
|
||||
uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data);
|
||||
#endif // __SCCB_H__
|
||||
28
code/lib/driver/sensor.c
Normal file
28
code/lib/driver/sensor.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "sensor.h"
|
||||
|
||||
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
|
||||
{ 96, 96, ASPECT_RATIO_1X1 }, /* 96x96 */
|
||||
{ 160, 120, ASPECT_RATIO_4X3 }, /* QQVGA */
|
||||
{ 176, 144, ASPECT_RATIO_5X4 }, /* QCIF */
|
||||
{ 240, 176, ASPECT_RATIO_4X3 }, /* HQVGA */
|
||||
{ 240, 240, ASPECT_RATIO_1X1 }, /* 240x240 */
|
||||
{ 320, 240, ASPECT_RATIO_4X3 }, /* QVGA */
|
||||
{ 400, 296, ASPECT_RATIO_4X3 }, /* CIF */
|
||||
{ 480, 320, ASPECT_RATIO_3X2 }, /* HVGA */
|
||||
{ 640, 480, ASPECT_RATIO_4X3 }, /* VGA */
|
||||
{ 800, 600, ASPECT_RATIO_4X3 }, /* SVGA */
|
||||
{ 1024, 768, ASPECT_RATIO_4X3 }, /* XGA */
|
||||
{ 1280, 720, ASPECT_RATIO_16X9 }, /* HD */
|
||||
{ 1280, 1024, ASPECT_RATIO_5X4 }, /* SXGA */
|
||||
{ 1600, 1200, ASPECT_RATIO_4X3 }, /* UXGA */
|
||||
// 3MP Sensors
|
||||
{ 1920, 1080, ASPECT_RATIO_16X9 }, /* FHD */
|
||||
{ 720, 1280, ASPECT_RATIO_9X16 }, /* Portrait HD */
|
||||
{ 864, 1536, ASPECT_RATIO_9X16 }, /* Portrait 3MP */
|
||||
{ 2048, 1536, ASPECT_RATIO_4X3 }, /* QXGA */
|
||||
// 5MP Sensors
|
||||
{ 2560, 1440, ASPECT_RATIO_16X9 }, /* QHD */
|
||||
{ 2560, 1600, ASPECT_RATIO_16X10 }, /* WQXGA */
|
||||
{ 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */
|
||||
{ 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */
|
||||
};
|
||||
191
code/lib/driver/sensor.h
Normal file
191
code/lib/driver/sensor.h
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* Sensor abstraction layer.
|
||||
*
|
||||
*/
|
||||
#ifndef __SENSOR_H__
|
||||
#define __SENSOR_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define OV9650_PID (0x96)
|
||||
#define OV7725_PID (0x77)
|
||||
#define OV2640_PID (0x26)
|
||||
#define OV3660_PID (0x36)
|
||||
#define OV5640_PID (0x56)
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
PIXFORMAT_YUV422, // 2BPP/YUV422
|
||||
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
||||
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
||||
PIXFORMAT_RGB888, // 3BPP/RGB888
|
||||
PIXFORMAT_RAW, // RAW
|
||||
PIXFORMAT_RGB444, // 3BP2P/RGB444
|
||||
PIXFORMAT_RGB555, // 3BP2P/RGB555
|
||||
} pixformat_t;
|
||||
|
||||
typedef enum {
|
||||
FRAMESIZE_96X96, // 96x96
|
||||
FRAMESIZE_QQVGA, // 160x120
|
||||
FRAMESIZE_QCIF, // 176x144
|
||||
FRAMESIZE_HQVGA, // 240x176
|
||||
FRAMESIZE_240X240, // 240x240
|
||||
FRAMESIZE_QVGA, // 320x240
|
||||
FRAMESIZE_CIF, // 400x296
|
||||
FRAMESIZE_HVGA, // 480x320
|
||||
FRAMESIZE_VGA, // 640x480
|
||||
FRAMESIZE_SVGA, // 800x600
|
||||
FRAMESIZE_XGA, // 1024x768
|
||||
FRAMESIZE_HD, // 1280x720
|
||||
FRAMESIZE_SXGA, // 1280x1024
|
||||
FRAMESIZE_UXGA, // 1600x1200
|
||||
// 3MP Sensors
|
||||
FRAMESIZE_FHD, // 1920x1080
|
||||
FRAMESIZE_P_HD, // 720x1280
|
||||
FRAMESIZE_P_3MP, // 864x1536
|
||||
FRAMESIZE_QXGA, // 2048x1536
|
||||
// 5MP Sensors
|
||||
FRAMESIZE_QHD, // 2560x1440
|
||||
FRAMESIZE_WQXGA, // 2560x1600
|
||||
FRAMESIZE_P_FHD, // 1080x1920
|
||||
FRAMESIZE_QSXGA, // 2560x1920
|
||||
FRAMESIZE_INVALID
|
||||
} framesize_t;
|
||||
|
||||
typedef enum {
|
||||
ASPECT_RATIO_4X3,
|
||||
ASPECT_RATIO_3X2,
|
||||
ASPECT_RATIO_16X10,
|
||||
ASPECT_RATIO_5X3,
|
||||
ASPECT_RATIO_16X9,
|
||||
ASPECT_RATIO_21X9,
|
||||
ASPECT_RATIO_5X4,
|
||||
ASPECT_RATIO_1X1,
|
||||
ASPECT_RATIO_9X16
|
||||
} aspect_ratio_t;
|
||||
|
||||
typedef enum {
|
||||
GAINCEILING_2X,
|
||||
GAINCEILING_4X,
|
||||
GAINCEILING_8X,
|
||||
GAINCEILING_16X,
|
||||
GAINCEILING_32X,
|
||||
GAINCEILING_64X,
|
||||
GAINCEILING_128X,
|
||||
} gainceiling_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t max_width;
|
||||
uint16_t max_height;
|
||||
uint16_t start_x;
|
||||
uint16_t start_y;
|
||||
uint16_t end_x;
|
||||
uint16_t end_y;
|
||||
uint16_t offset_x;
|
||||
uint16_t offset_y;
|
||||
uint16_t total_x;
|
||||
uint16_t total_y;
|
||||
} ratio_settings_t;
|
||||
|
||||
typedef struct {
|
||||
const uint16_t width;
|
||||
const uint16_t height;
|
||||
const aspect_ratio_t aspect_ratio;
|
||||
} resolution_info_t;
|
||||
|
||||
// Resolution table (in sensor.c)
|
||||
extern const resolution_info_t resolution[];
|
||||
|
||||
typedef struct {
|
||||
uint8_t MIDH;
|
||||
uint8_t MIDL;
|
||||
uint8_t PID;
|
||||
uint8_t VER;
|
||||
} sensor_id_t;
|
||||
|
||||
typedef struct {
|
||||
framesize_t framesize;//0 - 10
|
||||
bool scale;
|
||||
bool binning;
|
||||
uint8_t quality;//0 - 63
|
||||
int8_t brightness;//-2 - 2
|
||||
int8_t contrast;//-2 - 2
|
||||
int8_t saturation;//-2 - 2
|
||||
int8_t sharpness;//-2 - 2
|
||||
uint8_t denoise;
|
||||
uint8_t special_effect;//0 - 6
|
||||
uint8_t wb_mode;//0 - 4
|
||||
uint8_t awb;
|
||||
uint8_t awb_gain;
|
||||
uint8_t aec;
|
||||
uint8_t aec2;
|
||||
int8_t ae_level;//-2 - 2
|
||||
uint16_t aec_value;//0 - 1200
|
||||
uint8_t agc;
|
||||
uint8_t agc_gain;//0 - 30
|
||||
uint8_t gainceiling;//0 - 6
|
||||
uint8_t bpc;
|
||||
uint8_t wpc;
|
||||
uint8_t raw_gma;
|
||||
uint8_t lenc;
|
||||
uint8_t hmirror;
|
||||
uint8_t vflip;
|
||||
uint8_t dcw;
|
||||
uint8_t colorbar;
|
||||
} camera_status_t;
|
||||
|
||||
typedef struct _sensor sensor_t;
|
||||
typedef struct _sensor {
|
||||
sensor_id_t id; // Sensor ID.
|
||||
uint8_t slv_addr; // Sensor I2C slave address.
|
||||
pixformat_t pixformat;
|
||||
camera_status_t status;
|
||||
int xclk_freq_hz;
|
||||
|
||||
// Sensor function pointers
|
||||
int (*init_status) (sensor_t *sensor);
|
||||
int (*reset) (sensor_t *sensor);
|
||||
int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
|
||||
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
|
||||
int (*set_contrast) (sensor_t *sensor, int level);
|
||||
int (*set_brightness) (sensor_t *sensor, int level);
|
||||
int (*set_saturation) (sensor_t *sensor, int level);
|
||||
int (*set_sharpness) (sensor_t *sensor, int level);
|
||||
int (*set_denoise) (sensor_t *sensor, int level);
|
||||
int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
|
||||
int (*set_quality) (sensor_t *sensor, int quality);
|
||||
int (*set_colorbar) (sensor_t *sensor, int enable);
|
||||
int (*set_whitebal) (sensor_t *sensor, int enable);
|
||||
int (*set_gain_ctrl) (sensor_t *sensor, int enable);
|
||||
int (*set_exposure_ctrl) (sensor_t *sensor, int enable);
|
||||
int (*set_hmirror) (sensor_t *sensor, int enable);
|
||||
int (*set_vflip) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*set_aec2) (sensor_t *sensor, int enable);
|
||||
int (*set_awb_gain) (sensor_t *sensor, int enable);
|
||||
int (*set_agc_gain) (sensor_t *sensor, int gain);
|
||||
int (*set_aec_value) (sensor_t *sensor, int gain);
|
||||
|
||||
int (*set_special_effect) (sensor_t *sensor, int effect);
|
||||
int (*set_wb_mode) (sensor_t *sensor, int mode);
|
||||
int (*set_ae_level) (sensor_t *sensor, int level);
|
||||
|
||||
int (*set_dcw) (sensor_t *sensor, int enable);
|
||||
int (*set_bpc) (sensor_t *sensor, int enable);
|
||||
int (*set_wpc) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*set_raw_gma) (sensor_t *sensor, int enable);
|
||||
int (*set_lenc) (sensor_t *sensor, int enable);
|
||||
|
||||
int (*get_reg) (sensor_t *sensor, int reg, int mask);
|
||||
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
|
||||
int (*set_res_raw) (sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning);
|
||||
int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk);
|
||||
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
|
||||
} sensor_t;
|
||||
|
||||
#endif /* __SENSOR_H__ */
|
||||
432
code/lib/driver/twi.c
Normal file
432
code/lib/driver/twi.c
Normal file
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
si2c.c - Software I2C library for ESP31B
|
||||
|
||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the ESP31B core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "twi.h"
|
||||
#include "soc/gpio_reg.h"
|
||||
#include "soc/gpio_struct.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define LOW 0x0
|
||||
#define HIGH 0x1
|
||||
|
||||
//GPIO FUNCTIONS
|
||||
#define INPUT 0x01
|
||||
#define OUTPUT 0x02
|
||||
#define PULLUP 0x04
|
||||
#define INPUT_PULLUP 0x05
|
||||
#define PULLDOWN 0x08
|
||||
#define INPUT_PULLDOWN 0x09
|
||||
#define OPEN_DRAIN 0x10
|
||||
#define OUTPUT_OPEN_DRAIN 0x12
|
||||
#define SPECIAL 0xF0
|
||||
#define FUNCTION_1 0x00
|
||||
#define FUNCTION_2 0x20
|
||||
#define FUNCTION_3 0x40
|
||||
#define FUNCTION_4 0x60
|
||||
#define FUNCTION_5 0x80
|
||||
#define FUNCTION_6 0xA0
|
||||
|
||||
#define ESP_REG(addr) *((volatile uint32_t *)(addr))
|
||||
|
||||
const uint8_t pin_to_mux[40] = { 0x44, 0x88, 0x40, 0x84, 0x48, 0x6c, 0x60, 0x64, 0x68, 0x54, 0x58, 0x5c, 0x34, 0x38, 0x30, 0x3c, 0x4c, 0x50, 0x70, 0x74, 0x78, 0x7c, 0x80, 0x8c, 0, 0x24, 0x28, 0x2c, 0, 0, 0, 0, 0x1c, 0x20, 0x14, 0x18, 0x04, 0x08, 0x0c, 0x10};
|
||||
|
||||
static void pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
if(pin >= 40) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t rtc_reg = rtc_gpio_desc[pin].reg;
|
||||
|
||||
//RTC pins PULL settings
|
||||
if(rtc_reg) {
|
||||
//lock rtc
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
|
||||
if(mode & PULLUP) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown);
|
||||
} else if(mode & PULLDOWN) {
|
||||
ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup);
|
||||
} else {
|
||||
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
|
||||
}
|
||||
//unlock rtc
|
||||
}
|
||||
|
||||
uint32_t pinFunction = 0, pinControl = 0;
|
||||
|
||||
//lock gpio
|
||||
if(mode & INPUT) {
|
||||
if(pin < 32) {
|
||||
GPIO.enable_w1tc = BIT(pin);
|
||||
} else {
|
||||
GPIO.enable1_w1tc.val = BIT(pin - 32);
|
||||
}
|
||||
} else if(mode & OUTPUT) {
|
||||
if(pin > 33) {
|
||||
//unlock gpio
|
||||
return;//pins above 33 can be only inputs
|
||||
} else if(pin < 32) {
|
||||
GPIO.enable_w1ts = BIT(pin);
|
||||
} else {
|
||||
GPIO.enable1_w1ts.val = BIT(pin - 32);
|
||||
}
|
||||
}
|
||||
|
||||
if(mode & PULLUP) {
|
||||
pinFunction |= FUN_PU;
|
||||
} else if(mode & PULLDOWN) {
|
||||
pinFunction |= FUN_PD;
|
||||
}
|
||||
|
||||
pinFunction |= ((uint32_t)2 << FUN_DRV_S);//what are the drivers?
|
||||
pinFunction |= FUN_IE;//input enable but required for output as well?
|
||||
|
||||
if(mode & (INPUT | OUTPUT)) {
|
||||
pinFunction |= ((uint32_t)2 << MCU_SEL_S);
|
||||
} else if(mode == SPECIAL) {
|
||||
pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S);
|
||||
} else {
|
||||
pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S);
|
||||
}
|
||||
|
||||
ESP_REG(DR_REG_IO_MUX_BASE + pin_to_mux[pin]) = pinFunction;
|
||||
|
||||
if(mode & OPEN_DRAIN) {
|
||||
pinControl = (1 << GPIO_PIN0_PAD_DRIVER_S);
|
||||
}
|
||||
|
||||
GPIO.pin[pin].val = pinControl;
|
||||
//unlock gpio
|
||||
}
|
||||
|
||||
static void digitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
if(val) {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1ts = BIT(pin);
|
||||
} else if(pin < 34) {
|
||||
GPIO.out1_w1ts.val = BIT(pin - 32);
|
||||
}
|
||||
} else {
|
||||
if(pin < 32) {
|
||||
GPIO.out_w1tc = BIT(pin);
|
||||
} else if(pin < 34) {
|
||||
GPIO.out1_w1tc.val = BIT(pin - 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned char twi_dcount = 18;
|
||||
static unsigned char twi_sda, twi_scl;
|
||||
|
||||
|
||||
static inline void SDA_LOW()
|
||||
{
|
||||
//Enable SDA (becomes output and since GPO is 0 for the pin,
|
||||
// it will pull the line low)
|
||||
if (twi_sda < 32) {
|
||||
GPIO.enable_w1ts = BIT(twi_sda);
|
||||
} else {
|
||||
GPIO.enable1_w1ts.val = BIT(twi_sda - 32);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SDA_HIGH()
|
||||
{
|
||||
//Disable SDA (becomes input and since it has pullup it will go high)
|
||||
if (twi_sda < 32) {
|
||||
GPIO.enable_w1tc = BIT(twi_sda);
|
||||
} else {
|
||||
GPIO.enable1_w1tc.val = BIT(twi_sda - 32);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t SDA_READ()
|
||||
{
|
||||
if (twi_sda < 32) {
|
||||
return (GPIO.in & BIT(twi_sda)) != 0;
|
||||
} else {
|
||||
return (GPIO.in1.val & BIT(twi_sda - 32)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void SCL_LOW()
|
||||
{
|
||||
if (twi_scl < 32) {
|
||||
GPIO.enable_w1ts = BIT(twi_scl);
|
||||
} else {
|
||||
GPIO.enable1_w1ts.val = BIT(twi_scl - 32);
|
||||
}
|
||||
}
|
||||
|
||||
static void SCL_HIGH()
|
||||
{
|
||||
if (twi_scl < 32) {
|
||||
GPIO.enable_w1tc = BIT(twi_scl);
|
||||
} else {
|
||||
GPIO.enable1_w1tc.val = BIT(twi_scl - 32);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t SCL_READ()
|
||||
{
|
||||
if (twi_scl < 32) {
|
||||
return (GPIO.in & BIT(twi_scl)) != 0;
|
||||
} else {
|
||||
return (GPIO.in1.val & BIT(twi_scl - 32)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef FCPU80
|
||||
#define FCPU80 80000000L
|
||||
#endif
|
||||
|
||||
#if F_CPU == FCPU80
|
||||
#define TWI_CLOCK_STRETCH 800
|
||||
#else
|
||||
#define TWI_CLOCK_STRETCH 1600
|
||||
#endif
|
||||
|
||||
void twi_setClock(unsigned int freq)
|
||||
{
|
||||
#if F_CPU == FCPU80
|
||||
if(freq <= 100000) {
|
||||
twi_dcount = 19; //about 100KHz
|
||||
} else if(freq <= 200000) {
|
||||
twi_dcount = 8; //about 200KHz
|
||||
} else if(freq <= 300000) {
|
||||
twi_dcount = 3; //about 300KHz
|
||||
} else if(freq <= 400000) {
|
||||
twi_dcount = 1; //about 400KHz
|
||||
} else {
|
||||
twi_dcount = 1; //about 400KHz
|
||||
}
|
||||
#else
|
||||
if(freq <= 100000) {
|
||||
twi_dcount = 32; //about 100KHz
|
||||
} else if(freq <= 200000) {
|
||||
twi_dcount = 14; //about 200KHz
|
||||
} else if(freq <= 300000) {
|
||||
twi_dcount = 8; //about 300KHz
|
||||
} else if(freq <= 400000) {
|
||||
twi_dcount = 5; //about 400KHz
|
||||
} else if(freq <= 500000) {
|
||||
twi_dcount = 3; //about 500KHz
|
||||
} else if(freq <= 600000) {
|
||||
twi_dcount = 2; //about 600KHz
|
||||
} else {
|
||||
twi_dcount = 1; //about 700KHz
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void twi_init(unsigned char sda, unsigned char scl)
|
||||
{
|
||||
twi_sda = sda;
|
||||
twi_scl = scl;
|
||||
pinMode(twi_sda, OUTPUT);
|
||||
pinMode(twi_scl, OUTPUT);
|
||||
|
||||
digitalWrite(twi_sda, 0);
|
||||
digitalWrite(twi_scl, 0);
|
||||
|
||||
pinMode(twi_sda, INPUT_PULLUP);
|
||||
pinMode(twi_scl, INPUT_PULLUP);
|
||||
twi_setClock(100000);
|
||||
}
|
||||
|
||||
void twi_stop(void)
|
||||
{
|
||||
pinMode(twi_sda, INPUT);
|
||||
pinMode(twi_scl, INPUT);
|
||||
}
|
||||
|
||||
static void twi_delay(unsigned char v)
|
||||
{
|
||||
unsigned int i;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
|
||||
unsigned int reg;
|
||||
for(i=0; i<v; i++) {
|
||||
reg = REG_READ(GPIO_IN_REG);
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
static bool twi_write_start(void)
|
||||
{
|
||||
SCL_HIGH();
|
||||
SDA_HIGH();
|
||||
if (SDA_READ() == 0) {
|
||||
return false;
|
||||
}
|
||||
twi_delay(twi_dcount);
|
||||
SDA_LOW();
|
||||
twi_delay(twi_dcount);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool twi_write_stop(void)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
SCL_LOW();
|
||||
SDA_LOW();
|
||||
twi_delay(twi_dcount);
|
||||
SCL_HIGH();
|
||||
while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us)
|
||||
twi_delay(twi_dcount);
|
||||
SDA_HIGH();
|
||||
twi_delay(twi_dcount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool do_log = false;
|
||||
static bool twi_write_bit(bool bit)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
SCL_LOW();
|
||||
if (bit) {
|
||||
SDA_HIGH();
|
||||
if (do_log) {
|
||||
twi_delay(twi_dcount+1);
|
||||
}
|
||||
} else {
|
||||
SDA_LOW();
|
||||
if (do_log) {}
|
||||
}
|
||||
twi_delay(twi_dcount+1);
|
||||
SCL_HIGH();
|
||||
while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us)
|
||||
twi_delay(twi_dcount);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool twi_read_bit(void)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
SCL_LOW();
|
||||
SDA_HIGH();
|
||||
twi_delay(twi_dcount+2);
|
||||
SCL_HIGH();
|
||||
while (SCL_READ() == 0 && (i++) < TWI_CLOCK_STRETCH);// Clock stretching (up to 100us)
|
||||
bool bit = SDA_READ();
|
||||
twi_delay(twi_dcount);
|
||||
return bit;
|
||||
}
|
||||
|
||||
static bool twi_write_byte(unsigned char byte)
|
||||
{
|
||||
|
||||
if (byte == 0x43) {
|
||||
// printf("TWB %02x ", (uint32_t) byte);
|
||||
// do_log = true;
|
||||
}
|
||||
unsigned char bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
twi_write_bit((byte & 0x80) != 0);
|
||||
byte <<= 1;
|
||||
}
|
||||
if (do_log) {
|
||||
printf("\n");
|
||||
do_log = false;
|
||||
}
|
||||
return !twi_read_bit();//NACK/ACK
|
||||
}
|
||||
|
||||
static unsigned char twi_read_byte(bool nack)
|
||||
{
|
||||
unsigned char byte = 0;
|
||||
unsigned char bit;
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
byte = (byte << 1) | twi_read_bit();
|
||||
}
|
||||
twi_write_bit(nack);
|
||||
return byte;
|
||||
}
|
||||
|
||||
unsigned char twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop)
|
||||
{
|
||||
unsigned int i;
|
||||
if(!twi_write_start()) {
|
||||
return 4; //line busy
|
||||
}
|
||||
if(!twi_write_byte(((address << 1) | 0) & 0xFF)) {
|
||||
if (sendStop) {
|
||||
twi_write_stop();
|
||||
}
|
||||
return 2; //received NACK on transmit of address
|
||||
}
|
||||
for(i=0; i<len; i++) {
|
||||
if(!twi_write_byte(buf[i])) {
|
||||
if (sendStop) {
|
||||
twi_write_stop();
|
||||
}
|
||||
return 3;//received NACK on transmit of data
|
||||
}
|
||||
}
|
||||
if(sendStop) {
|
||||
twi_write_stop();
|
||||
}
|
||||
i = 0;
|
||||
while(SDA_READ() == 0 && (i++) < 10) {
|
||||
SCL_LOW();
|
||||
twi_delay(twi_dcount);
|
||||
SCL_HIGH();
|
||||
twi_delay(twi_dcount);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char twi_readFrom(unsigned char address, unsigned char* buf, unsigned int len, unsigned char sendStop)
|
||||
{
|
||||
unsigned int i;
|
||||
if(!twi_write_start()) {
|
||||
return 4; //line busy
|
||||
}
|
||||
if(!twi_write_byte(((address << 1) | 1) & 0xFF)) {
|
||||
if (sendStop) {
|
||||
twi_write_stop();
|
||||
}
|
||||
return 2;//received NACK on transmit of address
|
||||
}
|
||||
for(i=0; i<(len-1); i++) {
|
||||
buf[i] = twi_read_byte(false);
|
||||
}
|
||||
buf[len-1] = twi_read_byte(true);
|
||||
if(sendStop) {
|
||||
twi_write_stop();
|
||||
}
|
||||
i = 0;
|
||||
while(SDA_READ() == 0 && (i++) < 10) {
|
||||
SCL_LOW();
|
||||
twi_delay(twi_dcount);
|
||||
SCL_HIGH();
|
||||
twi_delay(twi_dcount);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
38
code/lib/driver/twi.h
Normal file
38
code/lib/driver/twi.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
twi.h - Software I2C library for ESP31B
|
||||
|
||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the ESP31B core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef SI2C_h
|
||||
#define SI2C_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void twi_init(unsigned char sda, unsigned char scl);
|
||||
void twi_stop(void);
|
||||
void twi_setClock(unsigned int freq);
|
||||
uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop);
|
||||
uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
64
code/lib/driver/xclk.c
Normal file
64
code/lib/driver/xclk.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "xclk.h"
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#else
|
||||
#include "esp_log.h"
|
||||
static const char* TAG = "camera_xclk";
|
||||
#endif
|
||||
|
||||
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
|
||||
{
|
||||
ledc_timer_config_t timer_conf;
|
||||
timer_conf.duty_resolution = 2;
|
||||
timer_conf.freq_hz = xclk_freq_hz;
|
||||
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4
|
||||
timer_conf.clk_cfg = LEDC_AUTO_CLK;
|
||||
#endif
|
||||
// timer_conf.clk_cfg = LEDC_USE_APB_CLK;
|
||||
|
||||
timer_conf.timer_num = (ledc_timer_t)ledc_timer;
|
||||
esp_err_t err = ledc_timer_config(&timer_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_timer_config failed for freq %d, rc=%x", xclk_freq_hz, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_err_t camera_enable_out_clock(camera_config_t* config)
|
||||
{
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
|
||||
esp_err_t err = xclk_timer_conf(config->ledc_timer, config->xclk_freq_hz);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ledc_channel_config_t ch_conf;
|
||||
ch_conf.gpio_num = config->pin_xclk;
|
||||
ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
|
||||
ch_conf.channel = config->ledc_channel;
|
||||
ch_conf.intr_type = LEDC_INTR_DISABLE;
|
||||
ch_conf.timer_sel = config->ledc_timer;
|
||||
ch_conf.duty = 2;
|
||||
ch_conf.hpoint = 0;
|
||||
err = ledc_channel_config(&ch_conf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void camera_disable_out_clock()
|
||||
{
|
||||
periph_module_disable(PERIPH_LEDC_MODULE);
|
||||
}
|
||||
7
code/lib/driver/xclk.h
Normal file
7
code/lib/driver/xclk.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "camera_common.h"
|
||||
|
||||
esp_err_t camera_enable_out_clock();
|
||||
|
||||
void camera_disable_out_clock();
|
||||
Reference in New Issue
Block a user