diff options
Diffstat (limited to 'fw/fe310/eos/dev')
-rw-r--r-- | fw/fe310/eos/dev/Makefile | 16 | ||||
-rw-r--r-- | fw/fe310/eos/dev/bq25895.c | 43 | ||||
-rw-r--r-- | fw/fe310/eos/dev/bq25895.h | 5 | ||||
-rw-r--r-- | fw/fe310/eos/dev/cam.c | 138 | ||||
-rw-r--r-- | fw/fe310/eos/dev/cam.h | 88 | ||||
-rw-r--r-- | fw/fe310/eos/dev/drv2605.h | 3 | ||||
-rw-r--r-- | fw/fe310/eos/dev/lcd.c | 546 | ||||
-rw-r--r-- | fw/fe310/eos/dev/lcd.h | 12 | ||||
-rw-r--r-- | fw/fe310/eos/dev/lsm9ds1.h | 4 | ||||
-rw-r--r-- | fw/fe310/eos/dev/ov2640.c | 861 | ||||
-rw-r--r-- | fw/fe310/eos/dev/ov2640.h | 8 | ||||
-rw-r--r-- | fw/fe310/eos/dev/ov2640_regs.h | 245 | ||||
-rw-r--r-- | fw/fe310/eos/dev/sdc_crypto.c | 51 | ||||
-rw-r--r-- | fw/fe310/eos/dev/sdc_crypto.h | 18 | ||||
-rw-r--r-- | fw/fe310/eos/dev/sdcard.c | 539 | ||||
-rw-r--r-- | fw/fe310/eos/dev/sdcard.h | 22 |
16 files changed, 2599 insertions, 0 deletions
diff --git a/fw/fe310/eos/dev/Makefile b/fw/fe310/eos/dev/Makefile new file mode 100644 index 0000000..83cb1f5 --- /dev/null +++ b/fw/fe310/eos/dev/Makefile @@ -0,0 +1,16 @@ +include ../../common.mk +CFLAGS += -I$(bsp_dir)/include + +obj = bq25895.o ov2640.o gt911.o + + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +%.o: %.S + $(CC) $(CFLAGS) -c $< + +all: $(obj) + +clean: + rm -f *.o diff --git a/fw/fe310/eos/dev/bq25895.c b/fw/fe310/eos/dev/bq25895.c new file mode 100644 index 0000000..b290926 --- /dev/null +++ b/fw/fe310/eos/dev/bq25895.c @@ -0,0 +1,43 @@ +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> + +#include "eos.h" +#include "pwr.h" +#include "i2c.h" +#include "bq25895.h" + +static int reg_read(uint8_t reg, uint8_t *data) { + return eos_i2c_read8(BQ25895_ADDR, reg, data, 1); +} + +static int reg_write(uint8_t reg, uint8_t data) { + return eos_i2c_write8(BQ25895_ADDR, reg, &data, 1); +} + +int eos_bq25895_init(uint8_t wakeup_cause) { + int rst = (wakeup_cause == EOS_PWR_WAKE_RST); + int i, rv = EOS_OK; + uint8_t data = 0; + + if (rst) { + rv = reg_write(0x14, 0x80); // reset + if (rv) printf("I2C ERROR 0x14\n"); + rv = reg_write(0x14, 0x00); // disable watchdog + if (rv) printf("I2C ERROR 0x14\n"); + rv = reg_write(0x07, 0x8d); // disable watchdog + if (rv) printf("I2C ERROR 0x07\n"); + rv = reg_write(0x00, 0x28); // 2.1A input current + if (rv) printf("I2C ERROR 0x00\n"); + rv = reg_write(0x02, 0x30); // enable ICO, disaable MaxCharge and D+/D- + if (rv) printf("I2C ERROR 0x02\n"); + } + + printf("BQ25895:\n"); + for (i=0; i<0x15; i++) { + rv = reg_read(i, &data); + if (!rv) printf("REG%02x: %02x\n", i, data); + } + + return EOS_OK; +} diff --git a/fw/fe310/eos/dev/bq25895.h b/fw/fe310/eos/dev/bq25895.h new file mode 100644 index 0000000..cbef36e --- /dev/null +++ b/fw/fe310/eos/dev/bq25895.h @@ -0,0 +1,5 @@ +#include <stdint.h> + +#define BQ25895_ADDR 0x6A + +int eos_bq25895_init(uint8_t wakeup_cause); diff --git a/fw/fe310/eos/dev/cam.c b/fw/fe310/eos/dev/cam.c new file mode 100644 index 0000000..43293af --- /dev/null +++ b/fw/fe310/eos/dev/cam.c @@ -0,0 +1,138 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "eos.h" +#include "spi.h" +#include "cam.h" + +const int _eos_cam_resolution[][2] = { + {0, 0 }, + // C/SIF Resolutions + {88, 72 }, /* QQCIF */ + {176, 144 }, /* QCIF */ + {352, 288 }, /* CIF */ + {88, 60 }, /* QQSIF */ + {176, 120 }, /* QSIF */ + {352, 240 }, /* SIF */ + // VGA Resolutions + {40, 30 }, /* QQQQVGA */ + {80, 60 }, /* QQQVGA */ + {160, 120 }, /* QQVGA */ + {320, 240 }, /* QVGA */ + {640, 480 }, /* VGA */ + {60, 40 }, /* HQQQVGA */ + {120, 80 }, /* HQQVGA */ + {240, 160 }, /* HQVGA */ + // FFT Resolutions + {64, 32 }, /* 64x32 */ + {64, 64 }, /* 64x64 */ + {128, 64 }, /* 128x64 */ + {128, 128 }, /* 128x128 */ + {320, 320 }, /* 128x128 */ + // Other + {128, 160 }, /* LCD */ + {128, 160 }, /* QQVGA2 */ + {720, 480 }, /* WVGA */ + {752, 480 }, /* WVGA2 */ + {800, 600 }, /* SVGA */ + {1024, 768 }, /* XGA */ + {1280, 1024}, /* SXGA */ + {1600, 1200}, /* UXGA */ + {1280, 720 }, /* HD */ + {1920, 1080}, /* FHD */ + {2560, 1440}, /* QHD */ + {2048, 1536}, /* QXGA */ + {2560, 1600}, /* WQXGA */ + {2592, 1944}, /* WQXGA2 */ +}; + +#define CAM_REG_CAPTURE_CTRL 0x01 +#define CAM_REG_FIFO_CTRL 0x04 + +#define CAM_REG_GPIO_DIR 0x05 +#define CAM_REG_GPIO_WR 0x06 +#define CAM_REG_GPIO_RD 0x45 + +#define CAM_REG_STATUS 0x41 + +#define CAM_REG_VER 0x40 + +#define CAM_REG_READ_BURST 0x3c +#define CAM_REG_READ_BYTE 0x3d + +#define CAM_REG_FIFO_SIZE1 0x42 +#define CAM_REG_FIFO_SIZE2 0x43 +#define CAM_REG_FIFO_SIZE3 0x44 + +#define CAM_VAL_FIFO_CTRL_CLEAR 0x01 +#define CAM_VAL_FIFO_CTRL_START 0x02 +#define CAM_VAL_FIFO_CTRL_RSTWR 0x10 +#define CAM_VAL_FIFO_CTRL_RSTRD 0x20 + +#define CAM_VAL_STATUS_VSYNC 0x01 +#define CAM_VAL_STATUS_SHUTTER 0x02 +#define CAM_VAL_STATUS_CPTDONE 0x08 + +#define CAM_VAL_GPIO_RST 0x01 +#define CAM_VAL_GPIO_PWRDN 0x02 +#define CAM_VAL_GPIO_PWREN 0x04 + +static uint8_t reg_read(uint8_t addr) { + uint8_t ret; + + eos_spi_cs_set(); + eos_spi_xchg8(addr, 0); + ret = eos_spi_xchg8(0, 0); + eos_spi_cs_clear(); + + return ret; +} + +static void reg_write(uint8_t addr, uint8_t val) { + eos_spi_cs_set(); + eos_spi_xchg8(addr | 0x80, 0); + eos_spi_xchg8(val, 0); + eos_spi_cs_clear(); +} + +void eos_cam_capture(void) { + reg_write(CAM_REG_FIFO_CTRL, CAM_VAL_FIFO_CTRL_START); +} + +int eos_cam_capture_done(void) { + return !!(reg_read(CAM_REG_STATUS) & CAM_VAL_STATUS_CPTDONE); +} + +void eos_cam_capture_wait(void) { + int done = 0; + + while (!done) { + done = eos_cam_capture_done(); + } +} + +uint32_t eos_cam_fbuf_size(void) { + uint32_t ret; + + ret = reg_read(CAM_REG_FIFO_SIZE1); + ret |= reg_read(CAM_REG_FIFO_SIZE2) << 8; + ret |= (reg_read(CAM_REG_FIFO_SIZE3) & 0x7f) << 16; + return ret; +} + +void eos_cam_fbuf_read(uint8_t *buffer, uint16_t sz, int first) { + int i; + + eos_spi_cs_set(); + eos_spi_xchg8(CAM_REG_READ_BURST, 0); + if (first) eos_spi_xchg8(0, 0); + + for (i=0; i<sz; i++) { + buffer[i] = eos_spi_xchg8(0, 0); + } + eos_spi_cs_clear(); +} + +void eos_cam_fbuf_done(void) { + reg_write(CAM_REG_FIFO_CTRL, CAM_VAL_FIFO_CTRL_CLEAR); +} diff --git a/fw/fe310/eos/dev/cam.h b/fw/fe310/eos/dev/cam.h new file mode 100644 index 0000000..f61757b --- /dev/null +++ b/fw/fe310/eos/dev/cam.h @@ -0,0 +1,88 @@ +#include <stdint.h> + +typedef enum { + PIXFORMAT_INVALID = 0, + PIXFORMAT_BINARY, // 1BPP/BINARY + PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE + PIXFORMAT_RGB565, // 2BPP/RGB565 + PIXFORMAT_YUV422, // 2BPP/YUV422 + PIXFORMAT_BAYER, // 1BPP/RAW + PIXFORMAT_JPEG, // JPEG/COMPRESSED +} pixformat_t; + +typedef enum { + FRAMESIZE_INVALID = 0, + // C/SIF Resolutions + FRAMESIZE_QQCIF, // 88x72 + FRAMESIZE_QCIF, // 176x144 + FRAMESIZE_CIF, // 352x288 + FRAMESIZE_QQSIF, // 88x60 + FRAMESIZE_QSIF, // 176x120 + FRAMESIZE_SIF, // 352x240 + // VGA Resolutions + FRAMESIZE_QQQQVGA, // 40x30 + FRAMESIZE_QQQVGA, // 80x60 + FRAMESIZE_QQVGA, // 160x120 + FRAMESIZE_QVGA, // 320x240 + FRAMESIZE_VGA, // 640x480 + FRAMESIZE_HQQQVGA, // 60x40 + FRAMESIZE_HQQVGA, // 120x80 + FRAMESIZE_HQVGA, // 240x160 + // FFT Resolutions + FRAMESIZE_64X32, // 64x32 + FRAMESIZE_64X64, // 64x64 + FRAMESIZE_128X64, // 128x64 + FRAMESIZE_128X128, // 128x128 + FRAMESIZE_320X320, // 320x320 + // Other + FRAMESIZE_LCD, // 128x160 + FRAMESIZE_QQVGA2, // 128x160 + FRAMESIZE_WVGA, // 720x480 + FRAMESIZE_WVGA2, // 752x480 + FRAMESIZE_SVGA, // 800x600 + FRAMESIZE_XGA, // 1024x768 + FRAMESIZE_SXGA, // 1280x1024 + FRAMESIZE_UXGA, // 1600x1200 + FRAMESIZE_HD, // 1280x720 + FRAMESIZE_FHD, // 1920x1080 + FRAMESIZE_QHD, // 2560x1440 + FRAMESIZE_QXGA, // 2048x1536 + FRAMESIZE_WQXGA, // 2560x1600 + FRAMESIZE_WQXGA2, // 2592x1944 +} framesize_t; + +typedef enum { + GAINCEILING_2X, + GAINCEILING_4X, + GAINCEILING_8X, + GAINCEILING_16X, + GAINCEILING_32X, + GAINCEILING_64X, + GAINCEILING_128X, +} gainceiling_t; + +typedef enum { + SDE_NORMAL, + SDE_NEGATIVE, +} sde_t; + +extern const int _eos_cam_resolution[][2]; + +#define IM_LOG2_2(x) (((x) & 0x2ULL) ? ( 2 ) : 1) // NO ({ ... }) ! +#define IM_LOG2_4(x) (((x) & 0xCULL) ? ( 2 + IM_LOG2_2((x) >> 2)) : IM_LOG2_2(x)) // NO ({ ... }) ! +#define IM_LOG2_8(x) (((x) & 0xF0ULL) ? ( 4 + IM_LOG2_4((x) >> 4)) : IM_LOG2_4(x)) // NO ({ ... }) ! +#define IM_LOG2_16(x) (((x) & 0xFF00ULL) ? ( 8 + IM_LOG2_8((x) >> 8)) : IM_LOG2_8(x)) // NO ({ ... }) ! +#define IM_LOG2_32(x) (((x) & 0xFFFF0000ULL) ? (16 + IM_LOG2_16((x) >> 16)) : IM_LOG2_16(x)) // NO ({ ... }) ! +#define IM_LOG2(x) (((x) & 0xFFFFFFFF00000000ULL) ? (32 + IM_LOG2_32((x) >> 32)) : IM_LOG2_32(x)) // NO ({ ... }) ! + +#define IM_MAX(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a > _b ? _a : _b; }) +#define IM_MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; }) +#define IM_DIV(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a / _b) : 0; }) +#define IM_MOD(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _b ? (_a % _b) : 0; }) + +void eos_cam_capture(void); +int eos_cam_capture_done(void); +void eos_cam_capture_wait(void); +uint32_t eos_cam_fbuf_size(void); +void eos_cam_fbuf_read(uint8_t *buffer, uint16_t sz, int first); +void eos_cam_fbuf_done(void); diff --git a/fw/fe310/eos/dev/drv2605.h b/fw/fe310/eos/dev/drv2605.h new file mode 100644 index 0000000..fe90a9b --- /dev/null +++ b/fw/fe310/eos/dev/drv2605.h @@ -0,0 +1,3 @@ +#include <stdint.h> + +#define DRV2605_ADDR 0x5A diff --git a/fw/fe310/eos/dev/lcd.c b/fw/fe310/eos/dev/lcd.c new file mode 100644 index 0000000..3080a13 --- /dev/null +++ b/fw/fe310/eos/dev/lcd.c @@ -0,0 +1,546 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +#include "encoding.h" +#include "platform.h" + +#include "eos.h" +#include "timer.h" +#include "i2s.h" +#include "net.h" +#include "spi_dev.h" +#include "eve/eve.h" + +#include "board.h" + +#include "lcd.h" + +#define BIT_PUT(b, pin) if (b) GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << (pin)); else GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << (pin)); +#define BIT_GET(pin) ((GPIO_REG(GPIO_INPUT_VAL) & (1 << (pin))) >> (pin)) + +#define SCK_UP { GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << IOF_SPI1_SCK); } +#define SCK_DN { GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << IOF_SPI1_SCK); } + +static inline void _sleep(int n) { + volatile int x = n; + + while(x) x--; +} + +int eos_lcd_select(void) { + if (eos_i2s_running()) return EOS_ERR_BUSY; + if (eos_spi_dev() != EOS_SPI_DEV_NET) return EOS_ERR_BUSY; + + eos_net_stop(); + + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << LCD_PIN_CS); + + GPIO_REG(GPIO_INPUT_EN) &= ~(1 << LCD_PIN_CS); + GPIO_REG(GPIO_OUTPUT_EN) |= (1 << LCD_PIN_CS); + + GPIO_REG(GPIO_IOF_EN) &= ~SPI_IOF_MASK; + + return EOS_OK; +} + +void eos_lcd_deselect(void) { + GPIO_REG(GPIO_IOF_EN) |= SPI_IOF_MASK; + eos_net_start(); +} + +void eos_lcd_cs_set(void) { + GPIO_REG(GPIO_OUTPUT_VAL) |= (1 << LCD_PIN_CS); +} + +void eos_lcd_cs_clear(void) { + GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1 << LCD_PIN_CS); +} + +/* sck frequency for r/w operations is 0.8Mhz */ +void eos_lcd_write(uint8_t dc, uint8_t data) { + int i; + + BIT_PUT(dc, IOF_SPI1_MOSI); + _sleep(10); + SCK_UP; + for (i=0; i<8; i++) { + _sleep(10); + SCK_DN; + BIT_PUT(data & 0x80, IOF_SPI1_MOSI); + _sleep(10); + SCK_UP; + data = data << 1; + } + _sleep(10); + SCK_DN; +} + +void eos_lcd_read(uint8_t *data) { + int i; + + *data = 0; + for (i=0; i<8; i++) { + _sleep(10); + *data = *data << 1; + *data |= BIT_GET(IOF_SPI1_MISO); + SCK_UP; + _sleep(10); + SCK_DN; + } +} + +static int _init(void) { + int rv; + uint8_t chip_id[3]; + + rv = eos_lcd_select(); + if (rv) return rv; + eos_lcd_cs_set(); + + /* LCD Setting */ + eos_lcd_write(0, 0xFF); // change to Page 1 CMD + eos_lcd_write(1, 0xFF); + eos_lcd_write(1, 0x98); + eos_lcd_write(1, 0x06); + eos_lcd_write(1, 0x04); + eos_lcd_write(1, 0x01); + + // eos_lcd_write(0, 0x08); // Output SDA + // eos_lcd_write(1, 0x10); + + eos_lcd_write(0, 0xFE); // enable read + eos_lcd_write(1, 0x81); + + eos_lcd_write(0, 0x00); // RDID4 + eos_lcd_read(&chip_id[0]); + + eos_lcd_write(0, 0x01); + eos_lcd_read(&chip_id[1]); + + eos_lcd_write(0, 0x02); + eos_lcd_read(&chip_id[2]); + + printf("LCD CHIP ID: %.2x%.2x%.2x\n", chip_id[0], chip_id[1], chip_id[2]); + + eos_lcd_write(0, 0xFE); // disable read + eos_lcd_write(1, 0x00); + + if (memcmp(chip_id, "\x98\x06\x04", sizeof(chip_id))) { + return EOS_ERR_ABSENT; + } + + eos_lcd_write(0, 0x20); // set DE/VSYNC mode + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x21); // DE = 1 Active + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x30); // resolution setting 480 X 854 + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x31); // inversion setting 2-dot + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x40); // BT AVDD,AVDD + eos_lcd_write(1, 0x16); + + eos_lcd_write(0, 0x41); + eos_lcd_write(1, 0x33); // 22 + + eos_lcd_write(0, 0x42); + eos_lcd_write(1, 0x03); // VGL=DDVDH+VCIP-DDVDL, VGH=2DDVDL-VCIP + + eos_lcd_write(0, 0x43); + eos_lcd_write(1, 0x09); // set VGH clamp level + + eos_lcd_write(0, 0x44); + eos_lcd_write(1, 0x06); // set VGL clamp level + + eos_lcd_write(0, 0x50); // VREG1 + eos_lcd_write(1, 0x88); + + eos_lcd_write(0, 0x51); // VREG2 + eos_lcd_write(1, 0x88); + + eos_lcd_write(0, 0x52); // flicker MSB + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x53); // flicker LSB + eos_lcd_write(1, 0x49); // VCOM + + eos_lcd_write(0, 0x55); // flicker + eos_lcd_write(1, 0x49); + + eos_lcd_write(0, 0x60); + eos_lcd_write(1, 0x07); + + eos_lcd_write(0, 0x61); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x62); + eos_lcd_write(1, 0x07); + + eos_lcd_write(0, 0x63); + eos_lcd_write(1, 0x00); + + /* Gamma Setting */ + eos_lcd_write(0, 0xA0); // positive Gamma + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0xA1); + eos_lcd_write(1, 0x09); + + eos_lcd_write(0, 0xA2); + eos_lcd_write(1, 0x11); + + eos_lcd_write(0, 0xA3); + eos_lcd_write(1, 0x0B); + + eos_lcd_write(0, 0xA4); + eos_lcd_write(1, 0x05); + + eos_lcd_write(0, 0xA5); + eos_lcd_write(1, 0x08); + + eos_lcd_write(0, 0xA6); + eos_lcd_write(1, 0x06); + + eos_lcd_write(0, 0xA7); + eos_lcd_write(1, 0x04); + + eos_lcd_write(0, 0xA8); + eos_lcd_write(1, 0x09); + + eos_lcd_write(0, 0xA9); + eos_lcd_write(1, 0x0C); + + eos_lcd_write(0, 0xAA); + eos_lcd_write(1, 0x15); + + eos_lcd_write(0, 0xAB); + eos_lcd_write(1, 0x08); + + eos_lcd_write(0, 0xAC); + eos_lcd_write(1, 0x0F); + + eos_lcd_write(0, 0xAD); + eos_lcd_write(1, 0x12); + + eos_lcd_write(0, 0xAE); + eos_lcd_write(1, 0x09); + + eos_lcd_write(0, 0xAF); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0xC0); // negative Gamma + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0xC1); + eos_lcd_write(1, 0x09); + + eos_lcd_write(0, 0xC2); + eos_lcd_write(1, 0x10); + + eos_lcd_write(0, 0xC3); + eos_lcd_write(1, 0x0C); + + eos_lcd_write(0, 0xC4); + eos_lcd_write(1, 0x05); + + eos_lcd_write(0, 0xC5); + eos_lcd_write(1, 0x08); + + eos_lcd_write(0, 0xC6); + eos_lcd_write(1, 0x06); + + eos_lcd_write(0, 0xC7); + eos_lcd_write(1, 0x04); + + eos_lcd_write(0, 0xC8); + eos_lcd_write(1, 0x08); + + eos_lcd_write(0, 0xC9); + eos_lcd_write(1, 0x0C); + + eos_lcd_write(0, 0xCA); + eos_lcd_write(1, 0x14); + + eos_lcd_write(0, 0xCB); + eos_lcd_write(1, 0x08); + + eos_lcd_write(0, 0xCC); + eos_lcd_write(1, 0x0F); + + eos_lcd_write(0, 0xCD); + eos_lcd_write(1, 0x11); + + eos_lcd_write(0, 0xCE); + eos_lcd_write(1, 0x09); + + eos_lcd_write(0, 0xCF); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0xFF); // change to Page 6 CMD for GIP timing + eos_lcd_write(1, 0xFF); + eos_lcd_write(1, 0x98); + eos_lcd_write(1, 0x06); + eos_lcd_write(1, 0x04); + eos_lcd_write(1, 0x06); + + eos_lcd_write(0, 0x00); + eos_lcd_write(1, 0x20); + + eos_lcd_write(0, 0x01); + eos_lcd_write(1, 0x0A); + + eos_lcd_write(0, 0x02); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x03); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x04); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x05); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x06); + eos_lcd_write(1, 0x98); + + eos_lcd_write(0, 0x07); + eos_lcd_write(1, 0x06); + + eos_lcd_write(0, 0x08); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x09); + eos_lcd_write(1, 0x80); + + eos_lcd_write(0, 0x0A); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x0B); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x0C); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x0D); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x0E); + eos_lcd_write(1, 0x05); + + eos_lcd_write(0, 0x0F); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x10); + eos_lcd_write(1, 0xF0); + + eos_lcd_write(0, 0x11); + eos_lcd_write(1, 0xF4); + + eos_lcd_write(0, 0x12); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x13); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x14); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x15); + eos_lcd_write(1, 0xC0); + + eos_lcd_write(0, 0x16); + eos_lcd_write(1, 0x08); + + eos_lcd_write(0, 0x17); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x18); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x19); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x1A); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x1B); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x1C); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x1D); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x20); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x21); + eos_lcd_write(1, 0x23); + + eos_lcd_write(0, 0x22); + eos_lcd_write(1, 0x45); + + eos_lcd_write(0, 0x23); + eos_lcd_write(1, 0x67); + + eos_lcd_write(0, 0x24); + eos_lcd_write(1, 0x01); + + eos_lcd_write(0, 0x25); + eos_lcd_write(1, 0x23); + + eos_lcd_write(0, 0x26); + eos_lcd_write(1, 0x45); + + eos_lcd_write(0, 0x27); + eos_lcd_write(1, 0x67); + + eos_lcd_write(0, 0x30); + eos_lcd_write(1, 0x11); + + eos_lcd_write(0, 0x31); + eos_lcd_write(1, 0x11); + + eos_lcd_write(0, 0x32); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x33); + eos_lcd_write(1, 0xEE); + + eos_lcd_write(0, 0x34); + eos_lcd_write(1, 0xFF); + + eos_lcd_write(0, 0x35); + eos_lcd_write(1, 0xBB); + + eos_lcd_write(0, 0x36); + eos_lcd_write(1, 0xAA); + + eos_lcd_write(0, 0x37); + eos_lcd_write(1, 0xDD); + + eos_lcd_write(0, 0x38); + eos_lcd_write(1, 0xCC); + + eos_lcd_write(0, 0x39); + eos_lcd_write(1, 0x66); + + eos_lcd_write(0, 0x3A); + eos_lcd_write(1, 0x77); + + eos_lcd_write(0, 0x3B); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0x3C); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0x3D); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0x3E); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0x3F); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0x40); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0xFF); // change to Page 7 CMD for GIP timing + eos_lcd_write(1, 0xFF); + eos_lcd_write(1, 0x98); + eos_lcd_write(1, 0x06); + eos_lcd_write(1, 0x04); + eos_lcd_write(1, 0x07); + + eos_lcd_write(0, 0x17); + eos_lcd_write(1, 0x22); + + eos_lcd_write(0, 0x02); + eos_lcd_write(1, 0x77); + + eos_lcd_write(0, 0x26); + eos_lcd_write(1, 0xB2); + + eos_lcd_write(0, 0xFF); // change to Page 0 CMD for normal command + eos_lcd_write(1, 0xFF); + eos_lcd_write(1, 0x98); + eos_lcd_write(1, 0x06); + eos_lcd_write(1, 0x04); + eos_lcd_write(1, 0x00); + + eos_lcd_write(0, 0x3A); + eos_lcd_write(1, 0x70); // 24BIT + + eos_lcd_write(0, 0x11); + eos_time_sleep(120); + eos_lcd_write(0, 0x29); + eos_time_sleep(25); + + eos_lcd_cs_clear(); + eos_lcd_deselect(); + + return EOS_OK; +} + +int eos_lcd_init(uint8_t wakeup_cause) { + eos_spi_select(EOS_SPI_DEV_EVE); + eve_gpio_set(EVE_GPIO_LCD_EN, 1); + eos_spi_deselect(); + eos_time_sleep(200); + + return _init(); +} + +int eos_lcd_sleep(void) { + int rv; + + rv = eos_lcd_select(); + if (rv) return rv; + + eos_lcd_cs_set(); + + eos_lcd_write(0, 0x28); + eos_time_sleep(10); + eos_lcd_write(0, 0x10); + + eos_lcd_cs_clear(); + eos_lcd_deselect(); + + eos_spi_select(EOS_SPI_DEV_EVE); + eve_gpio_set(EVE_GPIO_LCD_EN, 0); + eos_spi_deselect(); + + return EOS_OK; +} + +int eos_lcd_wake(void) { + int rv; + + eos_spi_select(EOS_SPI_DEV_EVE); + eve_gpio_set(EVE_GPIO_LCD_EN, 1); + eos_spi_deselect(); + eos_time_sleep(200); + + rv = eos_lcd_select(); + if (rv) return rv; + + eos_lcd_cs_set(); + + eos_lcd_write(0, 0x11); + eos_time_sleep(120); + eos_lcd_write(0, 0x29); + + eos_lcd_cs_clear(); + eos_lcd_deselect(); + + return EOS_OK; +} diff --git a/fw/fe310/eos/dev/lcd.h b/fw/fe310/eos/dev/lcd.h new file mode 100644 index 0000000..1bcb2cd --- /dev/null +++ b/fw/fe310/eos/dev/lcd.h @@ -0,0 +1,12 @@ +#include <stdint.h> + +int eos_lcd_init(uint8_t wakeup_cause); +int eos_lcd_select(void); +void eos_lcd_deselect(void); +void eos_lcd_cs_set(void); +void eos_lcd_cs_clear(void); +void eos_lcd_write(uint8_t dc, uint8_t data); +void eos_lcd_read(uint8_t *data); + +int eos_lcd_sleep(void); +int eos_lcd_wake(void);
\ No newline at end of file diff --git a/fw/fe310/eos/dev/lsm9ds1.h b/fw/fe310/eos/dev/lsm9ds1.h new file mode 100644 index 0000000..92220e7 --- /dev/null +++ b/fw/fe310/eos/dev/lsm9ds1.h @@ -0,0 +1,4 @@ +#include <stdint.h> + +#define LSM9DS1_ADDR_AG 0x1E +#define LSM9DS1_ADDR_M 0x6B diff --git a/fw/fe310/eos/dev/ov2640.c b/fw/fe310/eos/dev/ov2640.c new file mode 100644 index 0000000..6e54f10 --- /dev/null +++ b/fw/fe310/eos/dev/ov2640.c @@ -0,0 +1,861 @@ +#include <stdlib.h> +#include <stdint.h> +#include <math.h> + +#include "eos.h" +#include "timer.h" +#include "cam.h" + +#include "i2c.h" +#include "ov2640_regs.h" +#include "ov2640.h" + +#define XCLK_FREQ 24000000 +//#define XCLK_FREQ 12000000 + +#define CIF_WIDTH (400) +#define CIF_HEIGHT (296) + +#define SVGA_WIDTH (800) +#define SVGA_HEIGHT (600) + +#define UXGA_WIDTH (1600) +#define UXGA_HEIGHT (1200) + +static const uint8_t default_regs[][2] = { + +// From Linux Driver. + + {BANK_SEL, BANK_SEL_DSP}, + {0x2c, 0xff}, + {0x2e, 0xdf}, + {BANK_SEL, BANK_SEL_SENSOR}, + {0x3c, 0x32}, +// {CLKRC, CLKRC_DOUBLE | 0x02}, + {CLKRC, 0x01}, + {COM2, COM2_OUT_DRIVE_3x}, + {REG04, REG04_SET(REG04_HFLIP_IMG | REG04_VFLIP_IMG | REG04_VREF_EN | REG04_HREF_EN)}, + {COM8, COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN)}, + {COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, + {0x2c, 0x0c}, + {0x33, 0x78}, + {0x3a, 0x33}, + {0x3b, 0xfb}, + {0x3e, 0x00}, + {0x43, 0x11}, + {0x16, 0x10}, + {0x39, 0x02}, + {0x35, 0x88}, + {0x22, 0x0a}, + {0x37, 0x40}, + {0x23, 0x00}, + {ARCOM2, 0xa0}, + {0x06, 0x02}, + {0x06, 0x88}, + {0x07, 0xc0}, + {0x0d, 0xb7}, + {0x0e, 0x01}, + {0x4c, 0x00}, + {0x4a, 0x81}, + {0x21, 0x99}, + {AEW, 0x40}, + {AEB, 0x38}, + {VV, VV_AGC_TH_SET(0x08, 0x02)}, + {0x5c, 0x00}, + {0x63, 0x00}, + {FLL, 0x22}, + {COM3, COM3_BAND_SET(COM3_BAND_AUTO)}, + {REG5D, 0x55}, + {REG5E, 0x7d}, + {REG5F, 0x7d}, + {REG60, 0x55}, + {HISTO_LOW, 0x70}, + {HISTO_HIGH, 0x80}, + {0x7c, 0x05}, + {0x20, 0x80}, + {0x28, 0x30}, + {0x6c, 0x00}, + {0x6d, 0x80}, + {0x6e, 0x00}, + {0x70, 0x02}, + {0x71, 0x94}, + {0x73, 0xc1}, + {0x3d, 0x34}, + {COM7, COM7_RES_UXGA | COM7_ZOOM_EN}, + {0x5a, 0x57}, + {COM25, 0x00}, + {BD50, 0xbb}, + {BD60, 0x9c}, + {BANK_SEL, BANK_SEL_DSP}, + {0xe5, 0x7f}, + {MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL}, + {0x41, 0x24}, + {RESET, RESET_JPEG | RESET_DVP}, + {0x76, 0xff}, + {0x33, 0xa0}, + {0x42, 0x20}, + {0x43, 0x18}, + {0x4c, 0x00}, + {CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10}, + {0x88, 0x3f}, + {0xd7, 0x03}, + {0xd9, 0x10}, + {R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x2}, + {0xc8, 0x08}, + {0xc9, 0x80}, + {BPADDR, 0x00}, + {BPDATA, 0x00}, + {BPADDR, 0x03}, + {BPDATA, 0x48}, + {BPDATA, 0x48}, + {BPADDR, 0x08}, + {BPDATA, 0x20}, + {BPDATA, 0x10}, + {BPDATA, 0x0e}, + {0x90, 0x00}, + {0x91, 0x0e}, + {0x91, 0x1a}, + {0x91, 0x31}, + {0x91, 0x5a}, + {0x91, 0x69}, + {0x91, 0x75}, + {0x91, 0x7e}, + {0x91, 0x88}, + {0x91, 0x8f}, + {0x91, 0x96}, + {0x91, 0xa3}, + {0x91, 0xaf}, + {0x91, 0xc4}, + {0x91, 0xd7}, + {0x91, 0xe8}, + {0x91, 0x20}, + {0x92, 0x00}, + {0x93, 0x06}, + {0x93, 0xe3}, + {0x93, 0x03}, + {0x93, 0x03}, + {0x93, 0x00}, + {0x93, 0x02}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x93, 0x00}, + {0x96, 0x00}, + {0x97, 0x08}, + {0x97, 0x19}, + {0x97, 0x02}, + {0x97, 0x0c}, + {0x97, 0x24}, + {0x97, 0x30}, + {0x97, 0x28}, + {0x97, 0x26}, + {0x97, 0x02}, + {0x97, 0x98}, + {0x97, 0x80}, + {0x97, 0x00}, + {0x97, 0x00}, + {0xa4, 0x00}, + {0xa8, 0x00}, + {0xc5, 0x11}, + {0xc6, 0x51}, + {0xbf, 0x80}, + {0xc7, 0x10}, /* simple AWB */ + {0xb6, 0x66}, + {0xb8, 0xA5}, + {0xb7, 0x64}, + {0xb9, 0x7C}, + {0xb3, 0xaf}, + {0xb4, 0x97}, + {0xb5, 0xFF}, + {0xb0, 0xC5}, + {0xb1, 0x94}, + {0xb2, 0x0f}, + {0xc4, 0x5c}, + {0xa6, 0x00}, + {0xa7, 0x20}, + {0xa7, 0xd8}, + {0xa7, 0x1b}, + {0xa7, 0x31}, + {0xa7, 0x00}, + {0xa7, 0x18}, + {0xa7, 0x20}, + {0xa7, 0xd8}, + {0xa7, 0x19}, + {0xa7, 0x31}, + {0xa7, 0x00}, + {0xa7, 0x18}, + {0xa7, 0x20}, + {0xa7, 0xd8}, + {0xa7, 0x19}, + {0xa7, 0x31}, + {0xa7, 0x00}, + {0xa7, 0x18}, + {0x7f, 0x00}, + {0xe5, 0x1f}, + {0xe1, 0x77}, + {0xdd, 0x7f}, + {CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN}, + +// OpenMV Custom. + + {BANK_SEL, BANK_SEL_SENSOR}, + {0x0f, 0x4b}, + {COM1, 0x8f}, + +// End. + + {0xff, 0xff}, +}; + +// Looks really bad. +//static const uint8_t cif_regs[][2] = { +// {BANK_SEL, BANK_SEL_SENSOR}, +// {COM7, COM7_RES_CIF}, +// {COM1, 0x06 | 0x80}, +// {HSTART, 0x11}, +// {HSTOP, 0x43}, +// {VSTART, 0x01}, // 0x01 fixes issue with garbage pixels in the image... +// {VSTOP, 0x97}, +// {REG32, 0x09}, +// {BANK_SEL, BANK_SEL_DSP}, +// {RESET, RESET_DVP}, +// {SIZEL, SIZEL_HSIZE8_11_SET(CIF_WIDTH) | SIZEL_HSIZE8_SET(CIF_WIDTH) | SIZEL_VSIZE8_SET(CIF_HEIGHT)}, +// {HSIZE8, HSIZE8_SET(CIF_WIDTH)}, +// {VSIZE8, VSIZE8_SET(CIF_HEIGHT)}, +// {CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN}, +// {0, 0}, +//}; + +static const uint8_t svga_regs[][2] = { + {BANK_SEL, BANK_SEL_SENSOR}, + {COM7, COM7_RES_SVGA}, + {COM1, 0x0A | 0x80}, + {HSTART, 0x11}, + {HSTOP, 0x43}, + {VSTART, 0x01}, // 0x01 fixes issue with garbage pixels in the image... + {VSTOP, 0x97}, + {REG32, 0x09}, + {BANK_SEL, BANK_SEL_DSP}, + {RESET, RESET_DVP}, + {SIZEL, SIZEL_HSIZE8_11_SET(SVGA_WIDTH) | SIZEL_HSIZE8_SET(SVGA_WIDTH) | SIZEL_VSIZE8_SET(SVGA_HEIGHT)}, + {HSIZE8, HSIZE8_SET(SVGA_WIDTH)}, + {VSIZE8, VSIZE8_SET(SVGA_HEIGHT)}, + {CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN}, + {0xff, 0xff}, +}; + +static const uint8_t uxga_regs[][2] = { + {BANK_SEL, BANK_SEL_SENSOR}, + {COM7, COM7_RES_UXGA}, + {COM1, 0x0F | 0x80}, + {HSTART, 0x11}, + {HSTOP, 0x75}, + {VSTART, 0x01}, + {VSTOP, 0x97}, + {REG32, 0x36}, + {BANK_SEL, BANK_SEL_DSP}, + {RESET, RESET_DVP}, + {SIZEL, SIZEL_HSIZE8_11_SET(UXGA_WIDTH) | SIZEL_HSIZE8_SET(UXGA_WIDTH) | SIZEL_VSIZE8_SET(UXGA_HEIGHT)}, + {HSIZE8, HSIZE8_SET(UXGA_WIDTH)}, + {VSIZE8, VSIZE8_SET(UXGA_HEIGHT)}, + {CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN}, + {0xff, 0xff}, +}; + +static const uint8_t yuv422_regs[][2] = { + {BANK_SEL, BANK_SEL_DSP}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {IMAGE_MODE, IMAGE_MODE_YUV422}, + {0xd7, 0x03}, + {0x33, 0xa0}, + {0xe5, 0x1f}, + {0xe1, 0x67}, + {RESET, 0x00}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {0xff, 0xff}, +}; + +static const uint8_t rgb565_regs[][2] = { + {BANK_SEL, BANK_SEL_DSP}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {IMAGE_MODE, IMAGE_MODE_RGB565}, + {0xd7, 0x03}, + {RESET, 0x00}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {0xff, 0xff}, +}; + +static const uint8_t bayer_regs[][2] = { + {BANK_SEL, BANK_SEL_DSP}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {IMAGE_MODE, IMAGE_MODE_RAW10}, + {0xd7, 0x03}, + {RESET, 0x00}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {0xff, 0xff}, +}; + +static const uint8_t jpeg_regs[][2] = { + {BANK_SEL, BANK_SEL_DSP}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {IMAGE_MODE, IMAGE_MODE_JPEG_EN}, + {0xd7, 0x03}, + {RESET, 0x00}, + {R_BYPASS, R_BYPASS_DSP_EN}, + {0xff, 0xff}, +}; + +#define NUM_BRIGHTNESS_LEVELS (5) +static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = { + {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA}, + {0x00, 0x04, 0x09, 0x00, 0x00}, /* -2 */ + {0x00, 0x04, 0x09, 0x10, 0x00}, /* -1 */ + {0x00, 0x04, 0x09, 0x20, 0x00}, /* 0 */ + {0x00, 0x04, 0x09, 0x30, 0x00}, /* +1 */ + {0x00, 0x04, 0x09, 0x40, 0x00}, /* +2 */ +}; + +#define NUM_CONTRAST_LEVELS (5) +static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = { + {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA}, + {0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06}, /* -2 */ + {0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06}, /* -1 */ + {0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06}, /* 0 */ + {0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06}, /* +1 */ + {0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06}, /* +2 */ +}; + +#define NUM_SATURATION_LEVELS (5) +static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = { + {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA}, + {0x00, 0x02, 0x03, 0x28, 0x28}, /* -2 */ + {0x00, 0x02, 0x03, 0x38, 0x38}, /* -1 */ + {0x00, 0x02, 0x03, 0x48, 0x48}, /* 0 */ + {0x00, 0x02, 0x03, 0x58, 0x58}, /* +1 */ + {0x00, 0x02, 0x03, 0x68, 0x68}, /* +2 */ +}; + +static int reg_read(int8_t reg, uint8_t *data) { + return eos_i2c_read8(OV2640_ADDR, reg, data, 1); +} + +static int reg_write(uint8_t reg, uint8_t data) { + return eos_i2c_write8(OV2640_ADDR, reg, &data, 1); +} + +static int regarr_write(const uint8_t (*regs)[2]) { + int i, rv; + + i = 0; + rv = EOS_OK; + + while ((regs[i][0] != 0xff) || (regs[i][1] != 0xff)) { + if (!rv) rv = reg_write(regs[i][0], regs[i][1]); + i++; + } + + return rv; +} + +int eos_ov2640_init(void) { + int rv; + + // Reset all registers + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_write(COM7, COM7_SRST); + if (rv) return rv; + + // Delay 5 ms + eos_time_sleep(5); + + // Write default regsiters + rv = regarr_write(default_regs); + if (rv) return rv; + + // Delay 300 ms + eos_time_sleep(300); + + return EOS_OK; +} + +int eos_ov2640_sleep(int enable) { + uint8_t reg; + int rv; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(COM2, ®); + if (rv) return rv; + + if (enable) { + reg |= COM2_STDBY; + } else { + reg &= ~COM2_STDBY; + } + + // Write back register + return reg_write(COM2, reg); +} + +int eos_ov2640_set_pixfmt(pixformat_t fmt) { + const uint8_t (*regs)[2]; + + switch (fmt) { + case PIXFORMAT_RGB565: + regs = rgb565_regs; + break; + case PIXFORMAT_YUV422: + case PIXFORMAT_GRAYSCALE: + regs = yuv422_regs; + break; + case PIXFORMAT_BAYER: + regs = bayer_regs; + break; + case PIXFORMAT_JPEG: + regs = jpeg_regs; + break; + default: + return EOS_ERR; + } + + return regarr_write(regs); +} + +int eos_ov2640_set_framesize(framesize_t framesize) { + const uint8_t (*regs)[2]; + uint16_t sensor_w = 0; + uint16_t sensor_h = 0; + uint16_t w = _eos_cam_resolution[framesize][0]; + uint16_t h = _eos_cam_resolution[framesize][1]; + int rv; + + if ((w % 4) || (h % 4) || (w > UXGA_WIDTH) || (h > UXGA_HEIGHT)) { // w/h must be divisble by 4 + return EOS_ERR; + } + + // Looks really bad. + /* if ((w <= CIF_WIDTH) && (h <= CIF_HEIGHT)) { + regs = cif_regs; + sensor_w = CIF_WIDTH; + sensor_h = CIF_HEIGHT; + } else */ if ((w <= SVGA_WIDTH) && (h <= SVGA_HEIGHT)) { + regs = svga_regs; + sensor_w = SVGA_WIDTH; + sensor_h = SVGA_HEIGHT; + } else { + regs = uxga_regs; + sensor_w = UXGA_WIDTH; + sensor_h = UXGA_HEIGHT; + } + + // Write setup regsiters + rv = regarr_write(regs); + if (rv) return rv; + + uint64_t tmp_div = IM_MIN(sensor_w / w, sensor_h / h); + uint16_t log_div = IM_MIN(IM_LOG2(tmp_div) - 1, 3); + uint16_t div = 1 << log_div; + uint16_t w_mul = w * div; + uint16_t h_mul = h * div; + uint16_t x_off = (sensor_w - w_mul) / 2; + uint16_t y_off = (sensor_h - h_mul) / 2; + + rv = EOS_OK; + if (!rv) rv = reg_write(CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(log_div) | CTRLI_H_DIV_SET(log_div)); + if (!rv) rv = reg_write(HSIZE, HSIZE_SET(w_mul)); + if (!rv) rv = reg_write(VSIZE, VSIZE_SET(h_mul)); + if (!rv) rv = reg_write(XOFFL, XOFFL_SET(x_off)); + if (!rv) rv = reg_write(YOFFL, YOFFL_SET(y_off)); + if (!rv) rv = reg_write(VHYX, VHYX_HSIZE_SET(w_mul) | VHYX_VSIZE_SET(h_mul) | VHYX_XOFF_SET(x_off) | VHYX_YOFF_SET(y_off)); + if (!rv) rv = reg_write(TEST, TEST_HSIZE_SET(w_mul)); + if (!rv) rv = reg_write(ZMOW, ZMOW_OUTW_SET(w)); + if (!rv) rv = reg_write(ZMOH, ZMOH_OUTH_SET(h)); + if (!rv) rv = reg_write(ZMHH, ZMHH_OUTW_SET(w) | ZMHH_OUTH_SET(h)); + if (!rv) rv = reg_write(R_DVP_SP, div); + if (!rv) rv = reg_write(RESET, 0x00); + + return rv; +} + +int eos_ov2640_set_contrast(int level) { + int rv = EOS_OK; + + level += (NUM_CONTRAST_LEVELS / 2) + 1; + if (level <= 0 || level > NUM_CONTRAST_LEVELS) { + return EOS_ERR; + } + + /* Switch to DSP register bank */ + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + + /* Write contrast registers */ + for (int i=0; i<sizeof(contrast_regs[0])/sizeof(contrast_regs[0][0]); i++) { + if (!rv) rv = reg_write(contrast_regs[0][i], contrast_regs[level][i]); + } + + return rv; +} + +int eos_ov2640_set_brightness(int level) { + int rv = EOS_OK; + + level += (NUM_BRIGHTNESS_LEVELS / 2) + 1; + if (level <= 0 || level > NUM_BRIGHTNESS_LEVELS) { + return EOS_ERR; + } + + /* Switch to DSP register bank */ + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + + /* Write brightness registers */ + for (int i=0; i<sizeof(brightness_regs[0])/sizeof(brightness_regs[0][0]); i++) { + if (!rv) rv = reg_write(brightness_regs[0][i], brightness_regs[level][i]); + } + + return rv; +} + +int eos_ov2640_set_saturation(int level) { + int rv = EOS_OK; + + level += (NUM_SATURATION_LEVELS / 2) + 1; + if (level <= 0 || level > NUM_SATURATION_LEVELS) { + return EOS_ERR; + } + + /* Switch to DSP register bank */ + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + + /* Write saturation registers */ + for (int i=0; i<sizeof(saturation_regs[0])/sizeof(saturation_regs[0][0]); i++) { + if (!rv) rv = reg_write(saturation_regs[0][i], saturation_regs[level][i]); + } + + return rv; +} + +int eos_ov2640_set_gainceiling(gainceiling_t gainceiling) { + int rv = EOS_OK; + + /* Switch to SENSOR register bank */ + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + + /* Write gain ceiling register */ + if (!rv) rv = reg_write(COM9, COM9_AGC_SET(gainceiling)); + + return rv; +} + +int eos_ov2640_set_quality(int qs) { + int rv = EOS_OK; + + /* Switch to DSP register bank */ + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + + /* Write QS register */ + if (!rv) rv = reg_write(QS, qs); + + return rv; +} + +int eos_ov2640_set_colorbar(int enable) { + int rv = EOS_OK; + uint8_t reg; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(COM7, ®); + if (rv) return rv; + + if (enable) { + reg |= COM7_COLOR_BAR; + } else { + reg &= ~COM7_COLOR_BAR; + } + + return reg_write(COM7, reg); +} + +int eos_ov2640_set_auto_gain(int enable, float gain_db, float gain_db_ceiling) { + int rv = EOS_OK; + uint8_t reg; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(COM8, ®); + if (rv) return rv; + + rv = reg_write(COM8, (reg & (~COM8_AGC_EN)) | (enable ? COM8_AGC_EN : 0)); + if (rv) return rv; + + rv = EOS_OK; + if (enable && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) { + float gain_ceiling = IM_MAX(IM_MIN(expf((gain_db_ceiling / 20.0) * logf(10.0)), 128.0), 2.0); + + if (!rv) rv = reg_read(COM9, ®); + if (!rv) rv = reg_write(COM9, (reg & 0x1F) | (((int)ceilf(log2f(gain_ceiling)) - 1) << 5)); + } + + if (!enable && (!isnanf(gain_db)) && (!isinff(gain_db))) { + float gain = IM_MAX(IM_MIN(expf((gain_db / 20.0) * logf(10.0)), 32.0), 1.0); + + int gain_temp = roundf(log2f(IM_MAX(gain / 2.0, 1.0))); + int gain_hi = 0xF >> (4 - gain_temp); + int gain_lo = IM_MIN(roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15); + + if (!rv) rv = reg_write(GAIN, (gain_hi << 4) | (gain_lo << 0)); + } + + return rv; +} + +int eos_ov2640_get_gain_db(float *gain_db) { + int rv = EOS_OK; + uint8_t reg, gain; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(COM8, ®); + if (rv) return rv; + + // DISABLED + // if (reg & COM8_AGC_EN) { + // rv = reg_write(COM8, reg & (~COM8_AGC_EN)); + // if (rv) return rv; + // } + // DISABLED + + rv = reg_read(GAIN, &gain); + if (rv) return rv; + + // DISABLED + // if (reg & COM8_AGC_EN) { + // rv = reg_write(COM8, reg | COM8_AGC_EN); + // if (rv) return rv; + // } + // DISABLED + + int hi_gain = 1 << (((gain >> 7) & 1) + ((gain >> 6) & 1) + ((gain >> 5) & 1) + ((gain >> 4) & 1)); + float lo_gain = 1.0 + (((gain >> 0) & 0xF) / 16.0); + *gain_db = 20.0 * (logf(hi_gain * lo_gain) / logf(10.0)); + + return EOS_OK; +} + +int eos_ov2640_set_auto_exposure(int enable, int exposure_us) { + int rv = EOS_OK; + uint8_t reg; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(COM8, ®); + if (rv) return rv; + + rv = reg_write(COM8, COM8_SET_AEC(reg, (enable != 0))); + if (rv) return rv; + + if (!enable && (exposure_us >= 0)) { + rv = reg_read(COM7, ®); + if (rv) return rv; + + int t_line = 0; + + if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322; + if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390; + if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195; + + rv = reg_read(CLKRC, ®); + if (rv) return rv; + + int pll_mult = ((reg & CLKRC_DOUBLE) ? 2 : 1) * 3; + int clk_rc = (reg & CLKRC_DIVIDER_MASK) + 2; + + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + if (rv) return rv; + + rv = reg_read(IMAGE_MODE, ®); + if (rv) return rv; + + int t_pclk = 0; + + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2; + + int exposure = IM_MAX(IM_MIN(((exposure_us*(((XCLK_FREQ/clk_rc)*pll_mult)/1000000))/t_pclk)/t_line,0xFFFF),0x0000); + + if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + + if (!rv) rv = reg_read(REG04, ®); + if (!rv) rv = reg_write(REG04, (reg & 0xFC) | ((exposure >> 0) & 0x3)); + + if (!rv) rv = reg_read(AEC, ®); + if (!rv) rv = reg_write(AEC, (reg & 0x00) | ((exposure >> 2) & 0xFF)); + + if (!rv) rv = reg_read(REG45, ®); + if (!rv) rv = reg_write(REG45, (reg & 0xC0) | ((exposure >> 10) & 0x3F)); + } + + return rv; +} + +int eos_ov2640_get_exposure_us(int *exposure_us) { + int rv = EOS_OK; + uint8_t reg, aec_10, aec_92, aec_1510; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(COM8, ®); + if (rv) return rv; + + // DISABLED + // if (reg & COM8_AEC_EN) { + // rv = reg_write(COM8, reg & (~COM8_AEC_EN)); + // if (rv) return rv; + // } + // DISABLED + + rv = reg_read(REG04, &aec_10); + if (rv) return rv; + + rv = reg_read(AEC, &aec_92); + if (rv) return rv; + + rv = reg_read(REG45, &aec_1510); + if (rv) return rv; + + // DISABLED + // if (reg & COM8_AEC_EN) { + // rv = reg_write(COM8, reg | COM8_AEC_EN); + // if (rv) return rv; + // } + // DISABLED + + rv = reg_read(COM7, ®); + if (rv) return rv; + + int t_line = 0; + + if (COM7_GET_RES(reg) == COM7_RES_UXGA) t_line = 1600 + 322; + if (COM7_GET_RES(reg) == COM7_RES_SVGA) t_line = 800 + 390; + if (COM7_GET_RES(reg) == COM7_RES_CIF) t_line = 400 + 195; + + rv = reg_read(CLKRC, ®); + if (rv) return rv; + + int pll_mult = ((reg & CLKRC_DOUBLE) ? 2 : 1) * 3; + int clk_rc = (reg & CLKRC_DIVIDER_MASK) + 2; + + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + if (rv) return rv; + + rv = reg_read(IMAGE_MODE, ®); + if (rv) return rv; + + int t_pclk = 0; + + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_YUV422) t_pclk = 2; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RAW10) t_pclk = 1; + if (IMAGE_MODE_GET_FMT(reg) == IMAGE_MODE_RGB565) t_pclk = 2; + + uint16_t exposure = ((aec_1510 & 0x3F) << 10) + ((aec_92 & 0xFF) << 2) + ((aec_10 & 0x3) << 0); + *exposure_us = (exposure*t_line*t_pclk)/(((XCLK_FREQ/clk_rc)*pll_mult)/1000000); + + return EOS_OK; +} + +int eos_ov2640_set_auto_whitebal(int enable, float r_gain_db, float g_gain_db, float b_gain_db) { + int rv = EOS_OK; + uint8_t reg; + + rv = reg_write(BANK_SEL, BANK_SEL_DSP); + if (rv) return rv; + + rv = reg_read(CTRL1, ®); + if (rv) return rv; + + rv = reg_write(CTRL1, (reg & (~CTRL1_AWB)) | (enable ? CTRL1_AWB : 0)); + if (rv) return rv; + + if (!enable && (!isnanf(r_gain_db)) && (!isnanf(g_gain_db)) && (!isnanf(b_gain_db)) + && (!isinff(r_gain_db)) && (!isinff(g_gain_db)) && (!isinff(b_gain_db))) { + } + + return rv; +} + +int eos_ov2640_set_hmirror(int enable) { + int rv = EOS_OK; + uint8_t reg; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(REG04, ®); + if (rv) return rv; + + if (!enable) { // Already mirrored. + reg |= REG04_HFLIP_IMG; + } else { + reg &= ~REG04_HFLIP_IMG; + } + + return reg_write(REG04, reg); +} + +int eos_ov2640_set_vflip(int enable) { + int rv = EOS_OK; + uint8_t reg; + + rv = reg_write(BANK_SEL, BANK_SEL_SENSOR); + if (rv) return rv; + + rv = reg_read(REG04, ®); + if (rv) return rv; + + if (!enable) { // Already flipped. + reg |= REG04_VFLIP_IMG | REG04_VREF_EN; + } else { + reg &= ~(REG04_VFLIP_IMG | REG04_VREF_EN); + } + + return reg_write(REG04, reg); +} + +int eos_ov2640_set_effect(sde_t sde) { + int rv = EOS_OK; + + switch (sde) { + case SDE_NEGATIVE: + if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_DSP); + if (!rv) rv = reg_write(BPADDR, 0x00); + if (!rv) rv = reg_write(BPDATA, 0x40); + if (!rv) rv = reg_write(BPADDR, 0x05); + if (!rv) rv = reg_write(BPDATA, 0x80); + if (!rv) rv = reg_write(BPDATA, 0x80); + break; + case SDE_NORMAL: + if (!rv) rv = reg_write(BANK_SEL, BANK_SEL_DSP); + if (!rv) rv = reg_write(BPADDR, 0x00); + if (!rv) rv = reg_write(BPDATA, 0x00); + if (!rv) rv = reg_write(BPADDR, 0x05); + if (!rv) rv = reg_write(BPDATA, 0x80); + if (!rv) rv = reg_write(BPDATA, 0x80); + break; + default: + return EOS_ERR; + } + + return rv; +} diff --git a/fw/fe310/eos/dev/ov2640.h b/fw/fe310/eos/dev/ov2640.h new file mode 100644 index 0000000..3d08c2a --- /dev/null +++ b/fw/fe310/eos/dev/ov2640.h @@ -0,0 +1,8 @@ +#include <stdint.h> + +#define OV2640_ADDR 0x30 + +int eos_ov2640_init(void); +int eos_ov2640_sleep(int enable); +int eos_ov2640_set_pixfmt(pixformat_t fmt); +int eos_ov2640_set_framesize(framesize_t framesize); diff --git a/fw/fe310/eos/dev/ov2640_regs.h b/fw/fe310/eos/dev/ov2640_regs.h new file mode 100644 index 0000000..deb7521 --- /dev/null +++ b/fw/fe310/eos/dev/ov2640_regs.h @@ -0,0 +1,245 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io> + * Copyright (c) 2013-2021 Kwabena W. Agyeman <kwagyeman@openmv.io> + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * OV2640 register definitions. + */ +#ifndef __REG_REGS_H__ +#define __REG_REGS_H__ + +/* DSP register bank FF=0x00*/ + +#define QS 0x44 +#define HSIZE 0x51 +#define VSIZE 0x52 +#define XOFFL 0x53 +#define YOFFL 0x54 +#define VHYX 0x55 +#define DPRP 0x56 +#define TEST 0x57 +#define ZMOW 0x5A +#define ZMOH 0x5B +#define ZMHH 0x5C +#define BPADDR 0x7C +#define BPDATA 0x7D +#define SIZEL 0x8C +#define HSIZE8 0xC0 +#define VSIZE8 0xC1 +#define CTRL1 0xC3 +#define MS_SP 0xF0 +#define SS_ID 0xF7 +#define SS_CTRL 0xF7 +#define MC_AL 0xFA +#define MC_AH 0xFB +#define MC_D 0xFC +#define P_CMD 0xFD +#define P_STATUS 0xFE + +#define CTRLI 0x50 +#define CTRLI_LP_DP 0x80 +#define CTRLI_ROUND 0x40 + +#define CTRL0 0xC2 +#define CTRL0_AEC_EN 0x80 +#define CTRL0_AEC_SEL 0x40 +#define CTRL0_STAT_SEL 0x20 +#define CTRL0_VFIRST 0x10 +#define CTRL0_YUV422 0x08 +#define CTRL0_YUV_EN 0x04 +#define CTRL0_RGB_EN 0x02 +#define CTRL0_RAW_EN 0x01 + +#define CTRL2 0x86 +#define CTRL2_DCW_EN 0x20 +#define CTRL2_SDE_EN 0x10 +#define CTRL2_UV_ADJ_EN 0x08 +#define CTRL2_UV_AVG_EN 0x04 +#define CTRL2_CMX_EN 0x01 + +#define CTRL3 0x87 +#define CTRL3_BPC_EN 0x80 +#define CTRL3_WPC_EN 0x40 +#define R_DVP_SP 0xD3 +#define R_DVP_SP_AUTO_MODE 0x80 + +#define R_BYPASS 0x05 +#define R_BYPASS_DSP_EN 0x00 +#define R_BYPASS_DSP_BYPAS 0x01 + +#define IMAGE_MODE 0xDA +#define IMAGE_MODE_Y8_DVP_EN 0x40 +#define IMAGE_MODE_JPEG_EN 0x10 +#define IMAGE_MODE_YUV422 0x00 +#define IMAGE_MODE_RAW10 0x04 +#define IMAGE_MODE_RGB565 0x09 +#define IMAGE_MODE_HREF_VSYNC 0x02 +#define IMAGE_MODE_LBYTE_FIRST 0x01 +#define IMAGE_MODE_GET_FMT(x) ((x)&0xC) + +#define RESET 0xE0 +#define RESET_MICROC 0x40 +#define RESET_SCCB 0x20 +#define RESET_JPEG 0x10 +#define RESET_DVP 0x04 +#define RESET_IPU 0x02 +#define RESET_CIF 0x01 + +#define MC_BIST 0xF9 +#define MC_BIST_RESET 0x80 +#define MC_BIST_BOOT_ROM_SEL 0x40 +#define MC_BIST_12KB_SEL 0x20 +#define MC_BIST_12KB_MASK 0x30 +#define MC_BIST_512KB_SEL 0x08 +#define MC_BIST_512KB_MASK 0x0C +#define MC_BIST_BUSY_BIT_R 0x02 +#define MC_BIST_MC_RES_ONE_SH_W 0x02 +#define MC_BIST_LAUNCH 0x01 + +#define BANK_SEL 0xFF +#define BANK_SEL_DSP 0x00 +#define BANK_SEL_SENSOR 0x01 + +/* Sensor register bank FF=0x01*/ + +#define GAIN 0x00 +#define COM1 0x03 +#define REG_PID 0x0A +#define REG_VER 0x0B +#define COM4 0x0D +#define AEC 0x10 + +#define CLKRC 0x11 +#define CLKRC_DOUBLE 0x80 +#define CLKRC_DIVIDER_MASK 0x3F + +#define COM10 0x15 +#define HSTART 0x17 +#define HSTOP 0x18 +#define VSTART 0x19 +#define VSTOP 0x1A +#define MIDH 0x1C +#define MIDL 0x1D +#define AEW 0x24 +#define AEB 0x25 +#define REG2A 0x2A +#define FRARL 0x2B +#define ADDVSL 0x2D +#define ADDVSH 0x2E +#define YAVG 0x2F +#define HSDY 0x30 +#define HEDY 0x31 +#define ARCOM2 0x34 +#define REG45 0x45 +#define FLL 0x46 +#define FLH 0x47 +#define COM19 0x48 +#define ZOOMS 0x49 +#define COM22 0x4B +#define COM25 0x4E +#define BD50 0x4F +#define BD60 0x50 +#define REG5D 0x5D +#define REG5E 0x5E +#define REG5F 0x5F +#define REG60 0x60 +#define HISTO_LOW 0x61 +#define HISTO_HIGH 0x62 + +#define REG04 0x04 +#define REG04_DEFAULT 0x28 +#define REG04_HFLIP_IMG 0x80 +#define REG04_VFLIP_IMG 0x40 +#define REG04_VREF_EN 0x10 +#define REG04_HREF_EN 0x08 +#define REG04_SET(x) (REG04_DEFAULT|x) + +#define REG08 0x08 +#define COM2 0x09 +#define COM2_STDBY 0x10 +#define COM2_OUT_DRIVE_1x 0x00 +#define COM2_OUT_DRIVE_2x 0x01 +#define COM2_OUT_DRIVE_3x 0x02 +#define COM2_OUT_DRIVE_4x 0x03 + +#define COM3 0x0C +#define COM3_DEFAULT 0x38 +#define COM3_BAND_50Hz 0x04 +#define COM3_BAND_60Hz 0x00 +#define COM3_BAND_AUTO 0x02 +#define COM3_BAND_SET(x) (COM3_DEFAULT|x) + +#define COM7 0x12 +#define COM7_SRST 0x80 +#define COM7_RES_UXGA 0x00 /* UXGA */ +#define COM7_RES_SVGA 0x40 /* SVGA */ +#define COM7_RES_CIF 0x20 /* CIF */ +#define COM7_ZOOM_EN 0x04 /* Enable Zoom */ +#define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ +#define COM7_GET_RES(x) ((x)&0x70) + +#define COM8 0x13 +#define COM8_DEFAULT 0xC0 +#define COM8_BNDF_EN 0x20 /* Enable Banding filter */ +#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ +#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ +#define COM8_SET(x) (COM8_DEFAULT|x) +#define COM8_SET_AEC(r,x) (((r)&0xFE)|((x)&1)) + +#define COM9 0x14 /* AGC gain ceiling */ +#define COM9_DEFAULT 0x08 +#define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ +#define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ +#define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ +#define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ +#define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ +#define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ +#define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ +#define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) + +#define CTRL1_AWB 0x08 /* Enable AWB */ + +#define VV 0x26 +#define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) + +#define REG32 0x32 +#define REG32_UXGA 0x36 +#define REG32_SVGA 0x09 +#define REG32_CIF 0x00 + +#define VAL_SET(x, mask, rshift, lshift) ((((x) >> rshift) & mask) << lshift) + +#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3) +#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0) + +#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6) +#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3) +#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0) + +#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) +#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0) + +#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) +#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0) + +#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) +#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0) + +#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7) +#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3) +#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4) +#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0) + +#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7) + +#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0) +#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0) + +#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4) +#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2) +#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0) + +#endif //__REG_REGS_H__ diff --git a/fw/fe310/eos/dev/sdc_crypto.c b/fw/fe310/eos/dev/sdc_crypto.c new file mode 100644 index 0000000..f0e935d --- /dev/null +++ b/fw/fe310/eos/dev/sdc_crypto.c @@ -0,0 +1,51 @@ +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "sha/sha1.h" +#include "sdc_crypto.h" + +#define SDC_CRYPTO_KEY_SIZE 16 +#define SDC_CRYPTO_BLK_SIZE 16 +#define SDC_CRYPTO_HASH_SIZE 20 + +EOSSDCCrypto *sdc_crypto; + +void eos_sdcc_init(EOSSDCCrypto *crypto, uint8_t *key, void *ctx, eve_sdcc_init_t init, eve_sdcc_crypt_t enc, eve_sdcc_crypt_t dec, void *ctx_essiv, eve_sdcc_init_t init_essiv, eve_sdcc_essiv_t enc_essiv) { + char key_essiv[SDC_CRYPTO_HASH_SIZE]; + + sdc_crypto = crypto; + + memset(key_essiv, 0, SDC_CRYPTO_HASH_SIZE); + init(ctx, key); + sdc_crypto->ctx = ctx; + sdc_crypto->enc = enc; + sdc_crypto->dec = dec; + + SHA1(key_essiv, key, SDC_CRYPTO_KEY_SIZE); + init_essiv(ctx_essiv, key_essiv); + sdc_crypto->ctx_essiv = ctx_essiv; + sdc_crypto->enc_essiv = enc_essiv; +} + +void eos_sdcc_encrypt(uint32_t sect, uint8_t *buffer) { + uint8_t iv[SDC_CRYPTO_BLK_SIZE]; + + if (sdc_crypto == NULL) return; + + memset(iv, 0, SDC_CRYPTO_BLK_SIZE); + memcpy(iv, §, sizeof(sect)); + sdc_crypto->enc_essiv(sdc_crypto->ctx_essiv, iv); + sdc_crypto->enc(sdc_crypto->ctx, iv, buffer, 512); +} + +void eos_sdcc_decrypt(uint32_t sect, uint8_t *buffer) { + uint8_t iv[SDC_CRYPTO_BLK_SIZE]; + + if (sdc_crypto == NULL) return; + + memset(iv, 0, SDC_CRYPTO_BLK_SIZE); + memcpy(iv, §, sizeof(sect)); + sdc_crypto->enc_essiv(sdc_crypto->ctx_essiv, iv); + sdc_crypto->dec(sdc_crypto->ctx, iv, buffer, 512); +} diff --git a/fw/fe310/eos/dev/sdc_crypto.h b/fw/fe310/eos/dev/sdc_crypto.h new file mode 100644 index 0000000..015bf8a --- /dev/null +++ b/fw/fe310/eos/dev/sdc_crypto.h @@ -0,0 +1,18 @@ +#include <stddef.h> +#include <stdint.h> + +typedef void (*eve_sdcc_init_t) (void *, uint8_t *); +typedef void (*eve_sdcc_crypt_t) (void *, uint8_t *, uint8_t *, size_t); +typedef void (*eve_sdcc_essiv_t) (void *, uint8_t *); + +typedef struct EOSSDCCrypto { + void *ctx; + eve_sdcc_crypt_t enc; + eve_sdcc_crypt_t dec; + void *ctx_essiv; + eve_sdcc_essiv_t enc_essiv; +} EOSSDCCrypto; + +void eos_sdcc_init(EOSSDCCrypto *crypto, uint8_t *key, void *ctx, eve_sdcc_init_t init, eve_sdcc_crypt_t enc, eve_sdcc_crypt_t dec, void *ctx_essiv, eve_sdcc_init_t init_essiv, eve_sdcc_essiv_t enc_essiv); +void eos_sdcc_encrypt(uint32_t sect, uint8_t *buffer); +void eos_sdcc_decrypt(uint32_t sect, uint8_t *buffer);
\ No newline at end of file diff --git a/fw/fe310/eos/dev/sdcard.c b/fw/fe310/eos/dev/sdcard.c new file mode 100644 index 0000000..d081388 --- /dev/null +++ b/fw/fe310/eos/dev/sdcard.c @@ -0,0 +1,539 @@ +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> + +#include "eos.h" +#include "timer.h" + +#include "spi.h" +#include "spi_dev.h" + +#include "sdc_crypto.h" +#include "sdcard.h" + +#define SDC_TIMEOUT_CMD 500 +#define SDC_TIMEOUT_READ 200 +#define SDC_TIMEOUT_WRITE 500 + +#define SDC_POLY_CRC7 0x09 +#define SDC_POLY_CRC16 0x1021 + +#define SDC_CMD_FLAG_CRC 0x01 +#define SDC_CMD_FLAG_NOCS 0x02 +#define SDC_CMD_FLAG_NOWAIT 0x04 +#define SDC_CMD_FLAG_RSTUFF 0x08 + +#define SDC_TOKEN_START_BLK 0xfe +#define SDC_TOKEN_START_BLKM 0xfc +#define SDC_TOKEN_STOP_TRAN 0xfd + +#define SDC_DRESP_MASK 0x1f +#define SDC_DRESP_ACCEPT 0x05 +#define SDC_DRESP_ERR_CRC 0x0b +#define SDC_DRESP_ERR_WRITE 0x0d + +#define SDC_R1_READY 0x00 + +#define SDC_R1_IDLE_STATE 0x01 +#define SDC_R1_ERASE_RESET 0x02 +#define SDC_R1_ILLEGAL_CMD 0x04 +#define SDC_R1_ERR_CMD_CRC 0x08 +#define SDC_R1_ERR_ERASE_SEQ 0x10 +#define SDC_R1_ERR_ADDR 0x20 +#define SDC_R1_ERR_PARAM 0x40 + +#define SDC_NCR 10 + +#define SDC_ERR(rv) ((rv < 0) ? rv : EOS_ERR) + +/* CMD */ +#define GO_IDLE_STATE 0 +#define SEND_OP_COND 1 +#define SEND_IF_COND 8 +#define SEND_CSD 9 +#define STOP_TRANSMISSION 12 +#define SET_BLOCKLEN 16 +#define READ_SINGLE_BLOCK 17 +#define READ_MULTIPLE_BLOCK 18 +#define WRITE_BLOCK 24 +#define WRITE_MULTIPLE_BLOCK 25 +#define ERASE_WR_BLK_START 32 +#define ERASE_WR_BLK_END 33 +#define ERASE 38 +#define APP_CMD 55 +#define READ_OCR 58 + +/* ACMD */ +#define SD_STATUS 13 +#define SET_WR_BLK_ERASE_COUNT 23 +#define SD_APP_OP_COND 41 + +static uint8_t sdc_type = 0; + +static uint8_t sdc_crc7(uint8_t crc, uint8_t b) { + int i; + + for (i=8; i--; b<<=1) { + crc <<= 1; + if ((b ^ crc) & 0x80) crc ^= SDC_POLY_CRC7; + } + return crc & 0x7f; +} + +static uint16_t sdc_crc16(uint16_t crc, uint8_t b) { + int i; + + crc = crc ^ ((uint16_t)b << 8); + for (i=8; i--;) { + if (crc & 0x8000) { + crc = (crc << 1) ^ SDC_POLY_CRC16; + } else { + crc <<= 1; + } + } + return crc; +} + +static uint32_t sdc_nto(uint32_t start, uint32_t timeout) { + uint32_t d = eos_time_delta_ms(start); + return (d > timeout) ? 0 : timeout - d; +} + +static uint8_t sdc_xchg8(uint8_t data) { + return eos_spi_xchg8(data, 0); +} + +static uint16_t sdc_xchg16(uint16_t data) { + return eos_spi_xchg16(data, 0); +} + +static uint32_t sdc_xchg32(uint32_t data) { + return eos_spi_xchg32(data, 0); +} + +static void sdc_buf_send(unsigned char *buffer, uint16_t len) { + int i; + + for (i=0; i<len; i++) { + sdc_xchg8(buffer[i]); + } +} + +static void sdc_buf_recv(unsigned char *buffer, uint16_t len) { + int i; + + for (i=0; i<len; i++) { + buffer[i] = sdc_xchg8(0xff); + } +} + +static void sdc_select(void) { + eos_spi_cs_set(); + eos_spi_xchg8(0xff, 0); +} + +static void sdc_deselect(void) { + eos_spi_cs_clear(); + eos_spi_xchg8(0xff, 0); +} + +static int sdc_xchg_cmd(uint8_t cmd, uint32_t arg, uint8_t flags) { + int i; + uint8_t ret; + uint8_t crc = 0x7f; + + cmd |= 0x40; + if (flags & SDC_CMD_FLAG_CRC) { + crc = sdc_crc7(0, cmd); + crc = sdc_crc7(crc, arg >> 24); + crc = sdc_crc7(crc, arg >> 16); + crc = sdc_crc7(crc, arg >> 8); + crc = sdc_crc7(crc, arg); + } + crc = (crc << 1) | 0x01; + sdc_xchg8(cmd); + sdc_xchg32(arg); + sdc_xchg8(crc); + if (flags & SDC_CMD_FLAG_RSTUFF) sdc_xchg8(0xff); + + i = SDC_NCR; + do { + ret = sdc_xchg8(0xff); + } while ((ret & 0x80) && --i); + if (ret & 0x80) return EOS_ERR_BUSY; + + return ret; +} + +static int sdc_ready(uint32_t timeout) { + uint8_t d = 0; + uint32_t start; + + if (timeout == 0) return EOS_ERR_BUSY; + start = eos_time_get_tick(); + do { + if (eos_time_delta_ms(start) > timeout) break; + d = sdc_xchg8(0xff); + } while (d != 0xff); + if (d != 0xff) return EOS_ERR_BUSY; + + return EOS_OK; +} + +static int sdc_block_read(uint8_t *buffer, uint16_t len, uint32_t timeout) { + uint8_t token = 0xff; + uint32_t start; + + if (timeout == 0) return EOS_ERR_BUSY; + start = eos_time_get_tick(); + do { + if (eos_time_delta_ms(start) > timeout) break; + token = sdc_xchg8(0xff); + } while (token == 0xff); + if (token == 0xff) return EOS_ERR_BUSY; + if (token != SDC_TOKEN_START_BLK) return EOS_ERR; + + sdc_buf_recv(buffer, len); + sdc_xchg16(0xffff); /* dummy CRC */ + + return EOS_OK; +} + +static int sdc_block_write(uint8_t token, uint8_t *buffer, uint16_t len, uint32_t timeout) { + uint8_t d; + int rv; + + rv = sdc_ready(timeout); + if (rv) return rv; + + sdc_xchg8(token); + if (buffer && len) { + sdc_buf_send(buffer, len); + sdc_xchg16(0xffff); /* dummy CRC */ + + d = sdc_xchg8(0xff); /* Response */ + if ((d & SDC_DRESP_MASK) != SDC_DRESP_ACCEPT) return EOS_ERR; + } + + return EOS_OK; +} + +static int sdc_cmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) { + int do_cs = !(flags & SDC_CMD_FLAG_NOCS); + int do_wait = !(flags & SDC_CMD_FLAG_NOWAIT); + int rv = EOS_OK; + + if (do_cs) sdc_select(); + if (do_wait) rv = sdc_ready(timeout); + if (rv) { + if (do_cs) sdc_deselect(); + return rv; + } + rv = sdc_xchg_cmd(cmd, arg, flags); + if (do_cs) sdc_deselect(); + return rv; +} + +static int sdc_acmd(uint8_t cmd, uint32_t arg, uint8_t flags, uint32_t timeout) { + int rv; + uint32_t start; + + start = eos_time_get_tick(); + rv = sdc_cmd(APP_CMD, 0, flags, timeout); + if (rv & ~SDC_R1_IDLE_STATE) return rv; + + if (flags & SDC_CMD_FLAG_NOCS) { + sdc_deselect(); + sdc_select(); + } + return sdc_cmd(cmd, arg, flags, sdc_nto(start, timeout)); +} + +static int sdc_init(uint32_t timeout) { + int rv, i; + uint8_t _type; + uint8_t ocr[4]; + uint32_t start; + start = eos_time_get_tick(); + + eos_time_sleep(100); + for (i=10; i--;) sdc_xchg8(0xff); /* 80 dummy cycles */ + + rv = sdc_cmd(GO_IDLE_STATE, 0, SDC_CMD_FLAG_CRC, SDC_TIMEOUT_CMD); + if (rv != SDC_R1_IDLE_STATE) return SDC_ERR(rv); + + sdc_select(); + rv = sdc_cmd(SEND_IF_COND, 0x1aa, SDC_CMD_FLAG_CRC | SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout)); + switch (rv) { + case SDC_R1_IDLE_STATE: + for (i=0; i<4; i++) { /* R7 response */ + ocr[i] = sdc_xchg8(0xff); + } + sdc_deselect(); + if (ocr[2] == 0x01 && ocr[3] == 0xaa) { /* Check voltage range: 2.7-3.6V */ + do { + rv = sdc_acmd(SD_APP_OP_COND, 0x40000000, 0, sdc_nto(start, timeout)); + } while (rv == SDC_R1_IDLE_STATE); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + + sdc_select(); + rv = sdc_cmd(READ_OCR, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout)); + if (rv == SDC_R1_READY) { + for (i=0; i<4; i++) { /* R7 response */ + ocr[i] = sdc_xchg8(0xff); + } + sdc_deselect(); + } else { + sdc_deselect(); + return SDC_ERR(rv); + } + + _type = EOS_SDC_TYPE_SDC2; + if (ocr[0] & 0xc0) _type |= EOS_SDC_CAP_BLK; + } + break; + + case SDC_R1_IDLE_STATE | SDC_R1_ILLEGAL_CMD: + sdc_deselect(); + rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout)); + switch (rv) { + case SDC_R1_IDLE_STATE: + do { + rv = sdc_acmd(SD_APP_OP_COND, 0, 0, sdc_nto(start, timeout)); + } while (rv == SDC_R1_IDLE_STATE); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + case SDC_R1_READY: + _type = EOS_SDC_TYPE_SDC1; + break; + + default: + do { + rv = sdc_cmd(SEND_OP_COND, 0, 0, sdc_nto(start, timeout)); + } while (rv == SDC_R1_IDLE_STATE); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + _type = EOS_SDC_TYPE_MMC; + break; + + } + break; + + default: + sdc_deselect(); + return SDC_ERR(rv); + } + + if (!(_type & EOS_SDC_CAP_BLK)) { + rv = sdc_cmd(SET_BLOCKLEN, 512, 0, sdc_nto(start, timeout)); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + } + + if (_type & EOS_SDC_TYPE_SDC) { + uint8_t csd[16]; + + sdc_select(); + rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, sdc_nto(start, timeout)); + if (rv == SDC_R1_READY) { + rv = sdc_block_read(csd, 16, sdc_nto(start, timeout)); + } else { + rv = SDC_ERR(rv); + } + sdc_deselect(); + if (rv) return rv; + + for (i=0; i<16; i++) { + printf("%.2x ", csd[i]); + } + printf("\n"); + if (csd[10] & 0x40) _type |= EOS_SDC_CAP_ERASE_EN; + } + + eos_spi_set_div(EOS_SPI_DEV_SDC, 5); + sdc_type = _type; + return EOS_OK; +} + +int eos_sdc_init(uint8_t wakeup_cause) { + int rv; + + eos_spi_select(EOS_SPI_DEV_SDC); + rv = sdc_init(5000); + if (rv) { + printf("SDC ERROR\n"); + } else { + printf("SDC OK:%x\n", sdc_type); + } + eos_spi_deselect(); + + return EOS_OK; +} + +uint8_t eos_sdc_type(void) { + return sdc_type & EOS_SDC_TYPE_MASK; +} + +uint8_t eos_sdc_cap(void) { + return sdc_type & EOS_SDC_CAP_MASK; +} + +int eos_sdc_get_sect_count(uint32_t timeout, uint32_t *sectors) { + int rv; + uint8_t csd[16]; + uint32_t start = eos_time_get_tick(); + + sdc_select(); + rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, timeout); + if (rv == SDC_R1_READY) { + rv = sdc_block_read(csd, 16, sdc_nto(start, timeout)); + } else { + rv = SDC_ERR(rv); + } + sdc_deselect(); + if (rv) return rv; + + if ((csd[0] >> 6) == 1) { /* SDCv2 */ + *sectors = (csd[9] + (csd[8] << 8) + ((csd[7] & 0x3f) << 16) + 1) << 10; + } else { /* SDCv1 or MMC*/ + uint8_t n = (csd[5] & 0x0f) + (csd[10] >> 7) + ((csd[9] & 0x03) << 1) + 2; + *sectors = (csd[8] >> 6) + (csd[7] << 2) + ((csd[6] & 0x03) << 10) + 1; + *sectors = *sectors << (n - 9); + } + + return EOS_OK; +} + +int eos_sdc_get_blk_size(uint32_t timeout, uint32_t *size) { + int rv; + uint8_t rbl[64]; /* SD Status or CSD register */ + uint32_t start = eos_time_get_tick(); + + sdc_select(); + if (sdc_type & EOS_SDC_TYPE_SDC2) { + rv = sdc_acmd(SD_STATUS, 0, SDC_CMD_FLAG_NOCS, timeout); + sdc_xchg8(0xff); /* R2 response */ + } else { + rv = sdc_cmd(SEND_CSD, 0, SDC_CMD_FLAG_NOCS, timeout); + } + if (rv == SDC_R1_READY) { + rv = sdc_block_read(rbl, (sdc_type & EOS_SDC_TYPE_SDC2) ? 64 : 16, sdc_nto(start, timeout)); + } else { + rv = SDC_ERR(rv); + } + sdc_deselect(); + if (rv) return rv; + + if (sdc_type & EOS_SDC_TYPE_SDC2) { + *size = 16UL << (rbl[10] >> 4); + } else if (sdc_type & EOS_SDC_TYPE_SDC1) { + *size = (((rbl[10] & 0x3f) << 1) + (rbl[11] >> 7) + 1) << ((rbl[13] >> 6) - 1); + } else { + *size = (((rbl[10] & 0x7c) >> 2) + 1) * (((rbl[11] & 0x03) << 3) + (rbl[11] >> 5) + 1); + } + + return EOS_OK; +} + +int eos_sdc_sync(uint32_t timeout) { + int rv; + + sdc_select(); + rv = sdc_ready(timeout); + sdc_deselect(); + + return rv; +} + +int eos_sdc_erase(uint32_t blk_start, uint32_t blk_end, uint32_t timeout) { + int rv; + uint32_t start; + + if (!(sdc_type & EOS_SDC_TYPE_SDC)) return EOS_ERR; + if (!(sdc_type & EOS_SDC_CAP_ERASE_EN)) return EOS_ERR; + if (!(sdc_type & EOS_SDC_CAP_BLK)) { + blk_start *= 512; + blk_end *= 512; + } + + start = eos_time_get_tick(); + rv = sdc_cmd(ERASE_WR_BLK_START, blk_start, 0, timeout); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + + rv = sdc_cmd(ERASE_WR_BLK_END, blk_end, 0, sdc_nto(start, timeout)); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + + rv = sdc_cmd(ERASE, 0, 0, sdc_nto(start, timeout)); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + + return eos_sdc_sync(sdc_nto(start, timeout)); +} + +int eos_sdc_sect_read(uint32_t sect, unsigned int count, uint8_t *buffer) { + int rv; + uint8_t cmd = ((count == 1) ? READ_SINGLE_BLOCK : READ_MULTIPLE_BLOCK); + + if (!(sdc_type & EOS_SDC_CAP_BLK)) sect *= 512; + + sdc_select(); + rv = sdc_cmd(cmd, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD); + if (rv == SDC_R1_READY) { + int _rv = SDC_R1_READY; + + while (count) { + rv = sdc_block_read(buffer, 512, SDC_TIMEOUT_READ); + if (rv) break; + eos_sdcc_decrypt(sect, buffer); + buffer += 512; + count--; + } + if (cmd == READ_MULTIPLE_BLOCK) _rv = sdc_cmd(STOP_TRANSMISSION, 0, SDC_CMD_FLAG_NOCS | SDC_CMD_FLAG_NOWAIT | SDC_CMD_FLAG_RSTUFF, 0); + if (!rv && (_rv != SDC_R1_READY)) rv = SDC_ERR(_rv); + } else { + rv = SDC_ERR(rv); + } + sdc_deselect(); + + return rv; +} + +int eos_sdc_sect_write(uint32_t sect, unsigned int count, uint8_t *buffer) { + int rv; + + if (!(sdc_type & EOS_SDC_CAP_BLK)) sect *= 512; + + if (count == 1) { + sdc_select(); + rv = sdc_cmd(WRITE_BLOCK, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD); + if (rv == SDC_R1_READY) { + eos_sdcc_encrypt(sect, buffer); + rv = sdc_block_write(SDC_TOKEN_START_BLK, buffer, 512, SDC_TIMEOUT_WRITE); + } else { + rv = SDC_ERR(rv); + } + sdc_deselect(); + } else { + if (sdc_type & EOS_SDC_TYPE_SDC) { + rv = sdc_acmd(SET_WR_BLK_ERASE_COUNT, count, 0, SDC_TIMEOUT_CMD); + if (rv != SDC_R1_READY) return SDC_ERR(rv); + } + + sdc_select(); + rv = sdc_cmd(WRITE_MULTIPLE_BLOCK, sect, SDC_CMD_FLAG_NOCS, SDC_TIMEOUT_CMD); + if (rv == SDC_R1_READY) { + int _rv; + + while (count) { + eos_sdcc_encrypt(sect, buffer); + rv = sdc_block_write(SDC_TOKEN_START_BLKM, buffer, 512, SDC_TIMEOUT_WRITE); + if (rv) break; + buffer += 512; + count--; + } + _rv = sdc_block_write(SDC_TOKEN_STOP_TRAN, NULL, 0, SDC_TIMEOUT_WRITE); + if (!rv && (_rv != SDC_R1_READY)) rv = SDC_ERR(_rv); + } else { + rv = SDC_ERR(rv); + } + sdc_deselect(); + } + + return rv; +} diff --git a/fw/fe310/eos/dev/sdcard.h b/fw/fe310/eos/dev/sdcard.h new file mode 100644 index 0000000..910a6e0 --- /dev/null +++ b/fw/fe310/eos/dev/sdcard.h @@ -0,0 +1,22 @@ +#include <stdint.h> + +#define EOS_SDC_TYPE_MMC 0x01 + +#define EOS_SDC_TYPE_SDC1 0x04 +#define EOS_SDC_TYPE_SDC2 0x08 +#define EOS_SDC_TYPE_SDC 0x0c +#define EOS_SDC_TYPE_MASK 0x0f + +#define EOS_SDC_CAP_BLK 0x10 +#define EOS_SDC_CAP_ERASE_EN 0x20 +#define EOS_SDC_CAP_MASK 0xf0 + +int eos_sdc_init(uint8_t wakeup_cause); +uint8_t eos_sdc_type(void); +uint8_t eos_sdc_cap(void); +int eos_sdc_get_sect_count(uint32_t timeout, uint32_t *sectors); +int eos_sdc_get_blk_size(uint32_t timeout, uint32_t *size); +int eos_sdc_sync(uint32_t timeout); +int eos_sdc_erase(uint32_t blk_start, uint32_t blk_end, uint32_t timeout); +int eos_sdc_sect_read(uint32_t sect, unsigned int count, uint8_t *buffer); +int eos_sdc_sect_write(uint32_t sect, unsigned int count, uint8_t *buffer); |