From 701573ffe10499caf6a286b41f03bb800a1ebb91 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Tue, 5 Mar 2024 21:41:56 -0500 Subject: [PATCH 01/18] fully tested camera driver --- obc/config/obc_board_config.h | 6 +- obc/drivers/arducam/arducam.c | 16 ++-- obc/drivers/arducam/arducam.h | 9 +- obc/drivers/arducam/camera_reg.c | 14 +-- obc/drivers/arducam/camera_reg.h | 2 +- obc/drivers/arducam/ov5642_reg.c | 5 +- obc/drivers/arducam/ov5642_reg.h | 4 +- obc/examples/test_app_arducam/main.c | 124 +++++++++++++++++++++++++++ 8 files changed, 158 insertions(+), 22 deletions(-) create mode 100644 obc/examples/test_app_arducam/main.c diff --git a/obc/config/obc_board_config.h b/obc/config/obc_board_config.h index 2ba70d297..10c659c0e 100644 --- a/obc/config/obc_board_config.h +++ b/obc/config/obc_board_config.h @@ -26,8 +26,10 @@ #define CAM_SPI_PORT spiPORT3 #define CAM_SPI_REG spiREG3 #define CAM_SPI_DATA_FORMAT SPI_FMT_2 -#define CAM_CS_1 2UL -#define CAM_CS_2 3UL +// SPI3 CS[2] and CS[3] are used as I2C pins +// Reuse Some CS pins +#define CAM_CS_1 1UL +#define CAM_CS_2 1UL // State Manager DEBUG LED #define STATE_MGR_DEBUG_LED_GIO_PORT gioPORTB diff --git a/obc/drivers/arducam/arducam.c b/obc/drivers/arducam/arducam.c index 82e0a9c03..3dabfccf6 100644 --- a/obc/drivers/arducam/arducam.c +++ b/obc/drivers/arducam/arducam.c @@ -13,7 +13,7 @@ #define ARDUCHIP_FRAMES \ 0x01 // FRAME control register, Bit[2:0] = Number of frames to be captured // On 5MP_Plus platforms bit[2:0] = 7 // means continuous capture until frame buffer is full -#define CAP_DONE_MASK 0x04 +#define CAP_DONE_MASK 0x08 #define BURST_FIFO_READ 0x3C // Burst FIFO read operation #define ARDUCHIP_FIFO 0x04 // FIFO and I2C control @@ -42,6 +42,7 @@ obc_error_code_t initCam(void) { obc_error_code_t errCode; // Reset camera RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3008, 0x80)); + vTaskDelay(pdMS_TO_TICKS(2)); // Setup at 320x420 resolution RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamConfig(OV5642_QVGA_Preview_Config), PREVIEW_CONFIG_LEN)); vTaskDelay(pdMS_TO_TICKS(1)); @@ -60,7 +61,7 @@ obc_error_code_t initCam(void) { // Image horizontal control RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3801, 0xb0)); // Image compression - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x4407, 0x08)); + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x4407, 0x04)); // Lens correction RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x5888, 0x00)); // Image processor setup @@ -114,11 +115,13 @@ obc_error_code_t captureImage(camera_t cam) { obc_error_code_t errCode; errCode = flushFifo(cam); if (!errCode) { - errCode = startCapture(cam); + errCode = clearFifoFlag(cam); } + if (!errCode) { - errCode = clearFifoFlag(cam); + errCode = startCapture(cam); } + return errCode; } @@ -132,15 +135,14 @@ obc_error_code_t readFifoLength(uint32_t *length, camera_t cam) { RETURN_IF_ERROR_CODE(camReadReg(FIFO_SIZE1, &rx_data, cam)); len1 = rx_data; RETURN_IF_ERROR_CODE(camReadReg(FIFO_SIZE2, &rx_data, cam)); - len1 = rx_data; + len2 = rx_data; RETURN_IF_ERROR_CODE(camReadReg(FIFO_SIZE3, &rx_data, cam)); - len1 = (rx_data & 0x7f); + len3 = (rx_data & 0x7f); *length = ((len3 << 16) | (len2 << 8) | len1) & 0x07fffff; return errCode; } -// Todo: Not hardware tested obc_error_code_t readFifoBurst(camera_t cam) { obc_error_code_t errCode; int32_t file = 0; diff --git a/obc/drivers/arducam/arducam.h b/obc/drivers/arducam/arducam.h index 8e6debd1b..3036e264e 100644 --- a/obc/drivers/arducam/arducam.h +++ b/obc/drivers/arducam/arducam.h @@ -60,7 +60,7 @@ obc_error_code_t captureImage(camera_t cam); * @brief Read back image data * @param cam The camera to read from */ -obc_error_code_t readFifoBurst(camera_t cam); +obc_error_code_t readFifoBurst(uint8_t* buffer, size_t length, uint32_t* bytesWritten, camera_t cam); /** * @brief Checks if image capture has been completed @@ -68,3 +68,10 @@ obc_error_code_t readFifoBurst(camera_t cam); * @return Returns true if capture is complete */ bool isCaptureDone(camera_t cam); + +/** + * @brief Reads length of image in FIFO + * @param length pointer to uint32_t to store value + * @param cam The camera to check + */ +obc_error_code_t readFifoLength(uint32_t* length, camera_t cam); diff --git a/obc/drivers/arducam/camera_reg.c b/obc/drivers/arducam/camera_reg.c index 92bdfa5ea..bcfae5bfe 100644 --- a/obc/drivers/arducam/camera_reg.c +++ b/obc/drivers/arducam/camera_reg.c @@ -48,9 +48,9 @@ obc_error_code_t camReadReg(uint8_t addr, uint8_t *rx_data, camera_t cam) { obc_error_code_t camWriteByte(uint8_t byte, camera_t cam) { obc_error_code_t errCode; - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + // RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); errCode = spiTransmitByte(CAM_SPI_REG, &cam_config[cam].spi_config, byte); - RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + // RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); return errCode; } @@ -63,11 +63,11 @@ obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat) { return i2cSendTo(CAM_I2C_WR_ADDR, 3, reg_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); } -obc_error_code_t camReadSensorReg16_8(uint8_t regID, uint8_t *regDat) { - // Todo: regID is byteswapped for some reason so 0x3138 needs to be input as 0x3831 +obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t *regDat) { obc_error_code_t errCode; - RETURN_IF_ERROR_CODE(i2cSendTo(0x3C, 2, ®ID, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); - RETURN_IF_ERROR_CODE(i2cReceiveFrom(0x3C, 1, regDat, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); + uint8_t reg_id_tx_data[2] = {(regID >> 8), (regID & 0x00FF)}; + RETURN_IF_ERROR_CODE(i2cSendTo(CAM_I2C_WR_ADDR, 2, reg_id_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); + RETURN_IF_ERROR_CODE(i2cReceiveFrom(CAM_I2C_RD_ADDR, 1, regDat, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); return errCode; } @@ -94,6 +94,6 @@ obc_error_code_t tcaSelect(camera_t cam) { uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam) { uint8_t temp; camReadReg(addr, &temp, cam); - temp = temp & (1 << bit); + temp = temp & bit; return temp; } diff --git a/obc/drivers/arducam/camera_reg.h b/obc/drivers/arducam/camera_reg.h index 910e8452a..923dd9873 100644 --- a/obc/drivers/arducam/camera_reg.h +++ b/obc/drivers/arducam/camera_reg.h @@ -72,7 +72,7 @@ obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat); * @param regDat Buffer to store received data * @return Error code indicating if the read was successful */ -obc_error_code_t camReadSensorReg16_8(uint8_t regID, uint8_t* regDat); +obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t* regDat); /** * @brief Write to a list of registers over I2C diff --git a/obc/drivers/arducam/ov5642_reg.c b/obc/drivers/arducam/ov5642_reg.c index 2b590dcc5..e972ae75d 100644 --- a/obc/drivers/arducam/ov5642_reg.c +++ b/obc/drivers/arducam/ov5642_reg.c @@ -167,7 +167,8 @@ static sensor_reg_t OV5642_JPEG_Capture_QSXGA[JPEG_CONFIG_LEN] = { {0x3002, 0x0c}, // Reset for Individual Block, Reset SFIFO/compression {0x3002, 0x00}, // Reset for Individual Block {0x3503, 0x00}, // AEC Manual Mode Control, Auto enable - {0x5025, 0x80}, {0x3a0f, 0x48}, {0x3a10, 0x40}, {0x3a1b, 0x4a}, {0x3a1e, 0x3e}, {0x3a11, 0x70}, {0x3a1f, 0x20}, + {0x5025, 0x80}, {0x3a0f, 0x48}, {0x3a10, 0x40}, {0x3a1b, 0x4a}, + {0x3a1e, 0x3e}, {0x3a11, 0x70}, {0x3a1f, 0x20}, {0xffff, 0xff}, }; // Switch to lowest resolution @@ -175,7 +176,7 @@ static sensor_reg_t OV5642_320x240[RES_320_240_CONFIG_LEN] = { {0x3800, 0x1}, {0x3801, 0xa8}, {0x3802, 0x0}, {0x3803, 0xA}, {0x3804, 0xA}, {0x3805, 0x20}, {0x3806, 0x7}, {0x3807, 0x98}, {0x3808, 0x1}, {0x3809, 0x40}, {0x380a, 0x0}, {0x380b, 0xF0}, {0x380c, 0xc}, {0x380d, 0x80}, {0x380e, 0x7}, {0x380f, 0xd0}, {0x5001, 0x7f}, {0x5680, 0x0}, {0x5681, 0x0}, {0x5682, 0xA}, {0x5683, 0x20}, - {0x5684, 0x0}, {0x5685, 0x0}, {0x5686, 0x7}, {0x5687, 0x98}, {0x3801, 0xb0}, + {0x5684, 0x0}, {0x5685, 0x0}, {0x5686, 0x7}, {0x5687, 0x98}, {0x3801, 0xb0}, {0xffff, 0xff}, }; sensor_reg_t* getCamConfig(cam_config_t config) { diff --git a/obc/drivers/arducam/ov5642_reg.h b/obc/drivers/arducam/ov5642_reg.h index 2162569da..9c6942bd7 100644 --- a/obc/drivers/arducam/ov5642_reg.h +++ b/obc/drivers/arducam/ov5642_reg.h @@ -3,8 +3,8 @@ #include "stdint.h" #define PREVIEW_CONFIG_LEN 583 -#define JPEG_CONFIG_LEN 71 -#define RES_320_240_CONFIG_LEN 26 +#define JPEG_CONFIG_LEN 72 +#define RES_320_240_CONFIG_LEN 27 /** * @struct sensor_reg_t diff --git a/obc/examples/test_app_arducam/main.c b/obc/examples/test_app_arducam/main.c new file mode 100644 index 000000000..db85b810f --- /dev/null +++ b/obc/examples/test_app_arducam/main.c @@ -0,0 +1,124 @@ +#include "obc_logging.h" +#include "obc_errors.h" +#include "obc_sci_io.h" +#include "obc_spi_io.h" +#include "obc_i2c_io.h" +#include "obc_print.h" + +#include "arducam.h" +#include "camera_reg.h" + +#include +#include +#include +#include +#include +#include +#include + +#define UART_MUTEX_BLOCK_TIME portMAX_DELAY + +obc_error_code_t readFifoBurst2(uint32_t length) { + obc_error_code_t errCode; + uint8_t temp = 0, temp_last = 0; + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, 1)); + + // Set fifo to burst mode, receive continuous data until EOF + errCode = camWriteByte(0x3C, PRIMARY); + while (length-- && !errCode) { + temp_last = temp; + errCode = camReadByte(&temp, PRIMARY); + sciPrintf("0x%X,", temp); + if ((temp == 0xD9) && (temp_last == 0xFF)) { + break; + } + if (length % 30 == 0) { + sciPrintf("\r\n", temp); + } + // // Todo: Can this be changed to ~15us instead? + // vTaskDelay(pdMS_TO_TICKS(1)); + } + + if (!errCode) { + errCode = deassertChipSelect(CAM_SPI_PORT, 1); + } else { + // If there was an error during capture, deassert without an error check + deassertChipSelect(CAM_SPI_PORT, 1); + } + + return errCode; +} + +static StaticTask_t taskBuffer; +static StackType_t taskStack[1024]; + +void vTask1(void *pvParameters) { + sciPrintf("Starting Arducam Demo\r\n"); + // Read Camera ID + uint8_t cam_id[2] = {0}; + camReadSensorReg16_8(0x300A, &cam_id[0]); + camReadSensorReg16_8(0x300B, &cam_id[1]); + sciPrintf("Sensor ID: %X%X\r\n", cam_id[0], cam_id[1]); + camWriteReg(0x07, 0x80, PRIMARY); + vTaskDelay(pdMS_TO_TICKS(2)); + camWriteReg(0x07, 0x00, PRIMARY); + vTaskDelay(pdMS_TO_TICKS(2)); + uint8_t byte = 0x55; + sciPrintf("Writing %d to test reg\r\n", byte); + camWriteReg(0x00, byte, PRIMARY); + byte = 0; + camReadReg(0x00, &byte, PRIMARY); + sciPrintf("Read %d from test reg\r\n", byte); + camReadReg(0x00, &byte, PRIMARY); + sciPrintf("Read %d from test reg\r\n", byte); + setFormat(JPEG); + initCam(); + camWriteReg(0x03, 0x02, PRIMARY); + // camWriteSensorReg16_8(0x503d , 0x80); + // camWriteSensorReg16_8(0x503e, 0x00); + ov5642SetJpegSize(OV5642_320x240); + vTaskDelay(pdMS_TO_TICKS(2)); + + sciPrintf("Starting Image Capture\r\n"); + captureImage(PRIMARY); + while (!isCaptureDone(PRIMARY)) + ; + sciPrintf("Image Capture Done ^_^\r\n"); + + uint32_t img_len = 0; + readFifoLength(&img_len, PRIMARY); + sciPrintf("image len: %d \r\n", img_len); + + uint32_t first_half = img_len / 2; + uint32_t second_half = img_len - first_half; + + readFifoBurst2(first_half); + readFifoLength(&img_len, PRIMARY); + sciPrintf("image len: %d \r\n", img_len); + readFifoBurst2(second_half); + + while (1) + ; +} +int main(void) { + // Initialize hardware. + gioInit(); + sciInit(); + spiInit(); + i2cInit(); + + // Initialize the bus mutex. + initSciPrint(); + initSpiMutex(); + initI2CMutex(); + + xTaskCreateStatic(vTask1, "Arducam", 1024, NULL, 1, taskStack, &taskBuffer); + + vTaskStartScheduler(); + + while (1) + ; + + return 0; +} From 5606973a1edf9ed64231502e85df542663ec70e7 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Sun, 17 Mar 2024 15:50:58 -0400 Subject: [PATCH 02/18] combined all of the arducam functions into 1 file; Moved tca driver code into seperate file --- obc/drivers/CMakeLists.txt | 1 - obc/drivers/arducam/arducam.c | 85 ++++++++++++++++++++++++++- obc/drivers/arducam/arducam.h | 88 +++++++++++++++++++++++++++- obc/drivers/arducam/camera_reg.c | 99 -------------------------------- obc/drivers/arducam/camera_reg.h | 96 ------------------------------- obc/drivers/arducam/tca.c | 28 +++++++++ obc/drivers/arducam/tca.h | 13 +++++ 7 files changed, 211 insertions(+), 199 deletions(-) delete mode 100644 obc/drivers/arducam/camera_reg.c delete mode 100644 obc/drivers/arducam/camera_reg.h create mode 100644 obc/drivers/arducam/tca.c create mode 100644 obc/drivers/arducam/tca.h diff --git a/obc/drivers/CMakeLists.txt b/obc/drivers/CMakeLists.txt index 02247daed..8c24418f5 100644 --- a/obc/drivers/CMakeLists.txt +++ b/obc/drivers/CMakeLists.txt @@ -30,7 +30,6 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/rm46/obc_spi_dma.c ${CMAKE_CURRENT_SOURCE_DIR}/rm46/obc_dma.c ${CMAKE_CURRENT_SOURCE_DIR}/arducam/arducam.c - ${CMAKE_CURRENT_SOURCE_DIR}/arducam/camera_reg.c ${CMAKE_CURRENT_SOURCE_DIR}/arducam/ov5642_reg.c ${CMAKE_CURRENT_SOURCE_DIR}/cc1120/cc1120_mcu.c diff --git a/obc/drivers/arducam/arducam.c b/obc/drivers/arducam/arducam.c index 3dabfccf6..5a3a25c1b 100644 --- a/obc/drivers/arducam/arducam.c +++ b/obc/drivers/arducam/arducam.c @@ -1,12 +1,18 @@ #include "arducam.h" #include "ov5642_reg.h" + +#include "obc_i2c_io.h" #include "obc_spi_io.h" #include "obc_reliance_fs.h" #include "obc_board_config.h" +#include +#include +#include +#include #include -// Camera control +// Camera FIFO Control (SPI) defines #define ARDUCHIP_TRIG 0x41 // Trigger source #define ARDUCHIP_TIM 0x03 // Timing control #define VSYNC_LEVEL_MASK 0x02 // 0 = High active , 1 = Low active @@ -25,10 +31,23 @@ #define FIFO_SIZE2 0x43 // Camera write FIFO size[15:8] #define FIFO_SIZE3 0x44 // Camera write FIFO size[18:16] +// Camera Img Sensor (I2C) defines +#define CAM_I2C_ADDR 0x3C + +#define I2C_MUTEX_TIMEOUT portMAX_DELAY +#define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) + static uint8_t m_fmt; // Todo: support multiple image captures in different files static const char fname[] = "image.jpg"; +// SPI values +static spiDAT1_t arducamSPIDataFmt = {.CS_HOLD = 0, .CSNR = SPI_CS_NONE, .DFSEL = CAM_SPI_DATA_FORMAT, .WDEL = 0}; +static cam_settings_t cam_config[] = { + [PRIMARY] = {.cs_num = CAM_CS_1}, + [SECONDARY] = {.cs_num = CAM_CS_2}, +}; + void setFormat(image_format_t fmt) { if (fmt == BMP) m_fmt = BMP; @@ -204,3 +223,67 @@ obc_error_code_t readFifoBurst(camera_t cam) { return errCode; } + +uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam) { + uint8_t temp; + camReadReg(addr, &temp, cam); + temp = temp & bit; + return temp; +} + +obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam) { + obc_error_code_t errCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + addr = addr | 0x80; + uint8_t tx[2] = {addr, data}; + errCode = spiTransmitBytes(CAM_SPI_REG, &arducamSPIDataFmt, tx, 2); + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + return errCode; +} + +obc_error_code_t camReadReg(uint8_t addr, uint8_t *rx_data, camera_t cam) { + obc_error_code_t errCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + addr = addr & 0x7F; + errCode = spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, addr); + if (!errCode) { + errCode = spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, rx_data); + } + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + return errCode; +} + +obc_error_code_t camWriteByte(uint8_t byte, camera_t cam) { + obc_error_code_t errCode; + // RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + errCode = spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, byte); + // RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + return errCode; +} + +obc_error_code_t camReadByte(uint8_t *byte, camera_t cam) { + return spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, byte); +} + +obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat) { + uint8_t reg_tx_data[3] = {(regID >> 8), (regID & 0x00FF), regDat}; + return i2cSendTo(CAM_I2C_ADDR, 3, reg_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); +} + +obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t *regDat) { + obc_error_code_t errCode; + uint8_t reg_id_tx_data[2] = {(regID >> 8), (regID & 0x00FF)}; + RETURN_IF_ERROR_CODE(i2cSendTo(CAM_I2C_ADDR, 2, reg_id_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); + RETURN_IF_ERROR_CODE(i2cReceiveFrom(CAM_I2C_ADDR, 1, regDat, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); + return errCode; +} + +obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen) { + obc_error_code_t errCode; + + for (int i = 0; i < reglistLen; i++) { + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(reglist[i].reg, reglist[i].val)); + } + + return OBC_ERR_CODE_SUCCESS; +} diff --git a/obc/drivers/arducam/arducam.h b/obc/drivers/arducam/arducam.h index 3036e264e..51b5cd718 100644 --- a/obc/drivers/arducam/arducam.h +++ b/obc/drivers/arducam/arducam.h @@ -6,7 +6,17 @@ #include "obc_errors.h" #include "obc_logging.h" -#include "camera_reg.h" +#include "obc_spi_io.h" +#include "ov5642_reg.h" +#include "obc_board_config.h" + +/** + * @enum camera_t + * @brief Primary or secondary camera. + * + * Enum containing camera identifiers. + */ +typedef enum { PRIMARY, SECONDARY } camera_t; /** * @enum image_format_t @@ -60,7 +70,7 @@ obc_error_code_t captureImage(camera_t cam); * @brief Read back image data * @param cam The camera to read from */ -obc_error_code_t readFifoBurst(uint8_t* buffer, size_t length, uint32_t* bytesWritten, camera_t cam); +obc_error_code_t readFifoBurst(camera_t cam); /** * @brief Checks if image capture has been completed @@ -75,3 +85,77 @@ bool isCaptureDone(camera_t cam); * @param cam The camera to check */ obc_error_code_t readFifoLength(uint32_t* length, camera_t cam); + +/** + * @struct camera_settings_t + * @brief Camera settings struct + * + * Holds the settings for each camera. + */ +typedef struct { + uint8_t cs_num; +} cam_settings_t; + +/** + * @brief Write to a camera register over SPI + * @param addr Register address to write to + * @param data Data to send + * @param cam Camera identifier + * @return Error code indicating if the write was successful + */ +obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam); + +/** + * @brief Read a camera register over SPI + * @param addr Register address to read from + * @param rx_data Buffer to store received data + * @param cam Camera identifier + * @return Error code indicating if the read was successful + */ +obc_error_code_t camReadReg(uint8_t regID, uint8_t* regDat, camera_t cam); + +/** + * @brief Write one byte to a camera over SPI + * @param byte Camera settings struct + * @param cam Camera identifier + * @return Error code + */ +obc_error_code_t camWriteByte(uint8_t byte, camera_t cam); + +/** + * @brief Read one byte to a camera over SPI, does not handle CS assertion + * @param byte Camera settings struct + * @param cam Camera identifier + * @return Error code + */ +obc_error_code_t camReadByte(uint8_t* byte, camera_t cam); + +/** + * @brief Read 8 bits from a 16 bit register over I2C + * @param regID Register address to write to + * @param regDat Data to send + * @return Error code indicating if the write was successful + */ +obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat); + +/** + * @brief Write 8 bits to a 16 bit register over I2C + * @param regID Register address to read from + * @param regDat Buffer to store received data + * @return Error code indicating if the read was successful + */ +obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t* regDat); + +/** + * @brief Write to a list of registers over I2C + * @param reglist List of registers and data to write + * @return Error code indicating if the writes were successful + */ +obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen); + +/** + * @brief Read one bit from a register over SPI + * @param addr Address to read from + * @param bit Bit to read + */ +uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam); diff --git a/obc/drivers/arducam/camera_reg.c b/obc/drivers/arducam/camera_reg.c deleted file mode 100644 index bcfae5bfe..000000000 --- a/obc/drivers/arducam/camera_reg.c +++ /dev/null @@ -1,99 +0,0 @@ -#include -#include -#include "obc_i2c_io.h" -#include "obc_spi_io.h" -#include "obc_errors.h" -#include "obc_logging.h" -#include "obc_board_config.h" - -#include "ov5642_reg.h" -#include "camera_reg.h" - -#define CAM_I2C_WR_ADDR 0x3C -#define CAM_I2C_RD_ADDR 0x3C - -#define TCA_I2C_ADDR 0x70 - -#define I2C_MUTEX_TIMEOUT portMAX_DELAY -#define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) - -static cam_settings_t cam_config[] = { - [PRIMARY] = {.spi_config = {.CS_HOLD = false, .WDEL = false, .DFSEL = CAM_SPI_DATA_FORMAT, .CSNR = SPI_CS_NONE}, - .cs_num = CAM_CS_1}, - [SECONDARY] = {.spi_config = {.CS_HOLD = false, .WDEL = false, .DFSEL = CAM_SPI_DATA_FORMAT, .CSNR = SPI_CS_NONE}, - .cs_num = CAM_CS_2}, -}; - -obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam) { - obc_error_code_t errCode; - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - addr = addr | 0x80; - uint8_t tx[2] = {addr, data}; - errCode = spiTransmitBytes(CAM_SPI_REG, &cam_config[cam].spi_config, tx, 2); - RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - return errCode; -} - -obc_error_code_t camReadReg(uint8_t addr, uint8_t *rx_data, camera_t cam) { - obc_error_code_t errCode; - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - addr = addr & 0x7F; - errCode = spiTransmitByte(CAM_SPI_REG, &cam_config[cam].spi_config, addr); - if (!errCode) { - errCode = spiReceiveByte(CAM_SPI_REG, &cam_config[cam].spi_config, rx_data); - } - RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - return errCode; -} - -obc_error_code_t camWriteByte(uint8_t byte, camera_t cam) { - obc_error_code_t errCode; - // RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - errCode = spiTransmitByte(CAM_SPI_REG, &cam_config[cam].spi_config, byte); - // RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - return errCode; -} - -obc_error_code_t camReadByte(uint8_t *byte, camera_t cam) { - return spiReceiveByte(CAM_SPI_REG, &cam_config[cam].spi_config, byte); -} - -obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat) { - uint8_t reg_tx_data[3] = {(regID >> 8), (regID & 0x00FF), regDat}; - return i2cSendTo(CAM_I2C_WR_ADDR, 3, reg_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); -} - -obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t *regDat) { - obc_error_code_t errCode; - uint8_t reg_id_tx_data[2] = {(regID >> 8), (regID & 0x00FF)}; - RETURN_IF_ERROR_CODE(i2cSendTo(CAM_I2C_WR_ADDR, 2, reg_id_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); - RETURN_IF_ERROR_CODE(i2cReceiveFrom(CAM_I2C_RD_ADDR, 1, regDat, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); - return errCode; -} - -obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen) { - obc_error_code_t errCode; - - for (int i = 0; i < reglistLen; i++) { - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(reglist[i].reg, reglist[i].val)); - } - - return OBC_ERR_CODE_SUCCESS; -} - -obc_error_code_t tcaSelect(camera_t cam) { - uint8_t tca = 0; - if (cam == PRIMARY) { - tca = (1 << 0); - } else { - tca = (1 << 1); - } - return i2cSendTo(TCA_I2C_ADDR, 1, &tca, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); -} - -uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam) { - uint8_t temp; - camReadReg(addr, &temp, cam); - temp = temp & bit; - return temp; -} diff --git a/obc/drivers/arducam/camera_reg.h b/obc/drivers/arducam/camera_reg.h deleted file mode 100644 index 923dd9873..000000000 --- a/obc/drivers/arducam/camera_reg.h +++ /dev/null @@ -1,96 +0,0 @@ -#pragma once - -#include "stdint.h" -#include "obc_spi_io.h" -#include "ov5642_reg.h" -#include "obc_board_config.h" - -/** - * @enum camera_t - * @brief Primary or secondary camera. - * - * Enum containing camera identifiers. - */ -typedef enum { PRIMARY, SECONDARY } camera_t; - -/** - * @struct camera_settings_t - * @brief Camera settings struct - * - * Holds the settings for each camera. - */ -typedef struct { - spiDAT1_t spi_config; - uint8_t cs_num; -} cam_settings_t; - -/** - * @brief Write to a camera register over SPI - * @param addr Register address to write to - * @param data Data to send - * @param cam Camera identifier - * @return Error code indicating if the write was successful - */ -obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam); - -/** - * @brief Read a camera register over SPI - * @param addr Register address to read from - * @param rx_data Buffer to store received data - * @param cam Camera identifier - * @return Error code indicating if the read was successful - */ -obc_error_code_t camReadReg(uint8_t regID, uint8_t* regDat, camera_t cam); - -/** - * @brief Write one byte to a camera over SPI - * @param byte Camera settings struct - * @param cam Camera identifier - * @return Error code - */ -obc_error_code_t camWriteByte(uint8_t byte, camera_t cam); - -/** - * @brief Read one byte to a camera over SPI, does not handle CS assertion - * @param byte Camera settings struct - * @param cam Camera identifier - * @return Error code - */ -obc_error_code_t camReadByte(uint8_t* byte, camera_t cam); - -/** - * @brief Read 8 bits from a 16 bit register over I2C - * @param regID Register address to write to - * @param regDat Data to send - * @return Error code indicating if the write was successful - */ -obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat); - -/** - * @brief Write 8 bits to a 16 bit register over I2C - * @param regID Register address to read from - * @param regDat Buffer to store received data - * @return Error code indicating if the read was successful - */ -obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t* regDat); - -/** - * @brief Write to a list of registers over I2C - * @param reglist List of registers and data to write - * @return Error code indicating if the writes were successful - */ -obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen); - -/** - * @brief Select an I2C port on the TCA9458a multiplexer - * @param tca Port number to select - * @return Error code indicating if an ACK was received - */ -obc_error_code_t tcaSelect(camera_t cam); - -/** - * @brief Read one bit from a register over SPI - * @param addr Address to read from - * @param bit Bit to read - */ -uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam); diff --git a/obc/drivers/arducam/tca.c b/obc/drivers/arducam/tca.c new file mode 100644 index 000000000..7a330855e --- /dev/null +++ b/obc/drivers/arducam/tca.c @@ -0,0 +1,28 @@ +#include +#include +#include "obc_i2c_io.h" +#include "obc_spi_io.h" +#include "obc_errors.h" +#include "obc_logging.h" +#include "obc_board_config.h" + +#include "ov5642_reg.h" +#include "camera_reg.h" + +#define CAM_I2C_WR_ADDR 0x3C +#define CAM_I2C_RD_ADDR 0x3C + +#define TCA_I2C_ADDR 0x70 + +#define I2C_MUTEX_TIMEOUT portMAX_DELAY +#define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) + +obc_error_code_t tcaSelect(camera_t cam) { + uint8_t tca = 0; + if (cam == PRIMARY) { + tca = (1 << 0); + } else { + tca = (1 << 1); + } + return i2cSendTo(TCA_I2C_ADDR, 1, &tca, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); +} diff --git a/obc/drivers/arducam/tca.h b/obc/drivers/arducam/tca.h new file mode 100644 index 000000000..d4754efce --- /dev/null +++ b/obc/drivers/arducam/tca.h @@ -0,0 +1,13 @@ +#pragma once + +#include "stdint.h" +#include "obc_spi_io.h" +#include "ov5642_reg.h" +#include "obc_board_config.h" + +/** + * @brief Select an I2C port on the TCA9458a multiplexer + * @param tca Port number to select + * @return Error code indicating if an ACK was received + */ +obc_error_code_t tcaSelect(camera_t cam); From c677729ed2cd92f6c8b2c277c8e56508196a8ad6 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Sun, 31 Mar 2024 19:16:31 -0400 Subject: [PATCH 03/18] Cleaned up SPI driver of the Arducam Driver; Moved TCA9458a into own folder; moved image_processing files to payload mgr folder; initial commit of camera_control file --- obc/drivers/CMakeLists.txt | 1 + obc/drivers/arducam/arducam.c | 601 ++++++++++++------ obc/drivers/arducam/arducam.h | 224 ++++--- obc/drivers/arducam/ov5642_reg.c | 17 +- obc/drivers/arducam/ov5642_reg.h | 20 +- .../{arducam/tca.c => tca9458a/tca9458a.c} | 17 +- .../{arducam/tca.h => tca9458a/tca9458a.h} | 2 +- obc/examples/test_app_arducam/main.c | 2 +- obc/modules/CMakeLists.txt | 1 + obc/modules/camera_mgr/camera_control.c | 58 ++ obc/modules/camera_mgr/camera_control.h | 23 + .../camera_mgr}/image_processing.c | 0 .../camera_mgr}/image_processing.h | 0 13 files changed, 673 insertions(+), 293 deletions(-) rename obc/drivers/{arducam/tca.c => tca9458a/tca9458a.c} (63%) rename obc/drivers/{arducam/tca.h => tca9458a/tca9458a.h} (86%) create mode 100644 obc/modules/camera_mgr/camera_control.c create mode 100644 obc/modules/camera_mgr/camera_control.h rename obc/{drivers/arducam => modules/camera_mgr}/image_processing.c (100%) rename obc/{drivers/arducam => modules/camera_mgr}/image_processing.h (100%) diff --git a/obc/drivers/CMakeLists.txt b/obc/drivers/CMakeLists.txt index 8c24418f5..0382cba16 100644 --- a/obc/drivers/CMakeLists.txt +++ b/obc/drivers/CMakeLists.txt @@ -29,6 +29,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/rm46/obc_so_handling.c ${CMAKE_CURRENT_SOURCE_DIR}/rm46/obc_spi_dma.c ${CMAKE_CURRENT_SOURCE_DIR}/rm46/obc_dma.c + ${CMAKE_CURRENT_SOURCE_DIR}/arducam/arducam.c ${CMAKE_CURRENT_SOURCE_DIR}/arducam/ov5642_reg.c diff --git a/obc/drivers/arducam/arducam.c b/obc/drivers/arducam/arducam.c index 5a3a25c1b..f05dbffb8 100644 --- a/obc/drivers/arducam/arducam.c +++ b/obc/drivers/arducam/arducam.c @@ -11,258 +11,491 @@ #include #include #include - -// Camera FIFO Control (SPI) defines -#define ARDUCHIP_TRIG 0x41 // Trigger source -#define ARDUCHIP_TIM 0x03 // Timing control -#define VSYNC_LEVEL_MASK 0x02 // 0 = High active , 1 = Low active -#define ARDUCHIP_FRAMES \ - 0x01 // FRAME control register, Bit[2:0] = Number of frames to be captured // On 5MP_Plus platforms bit[2:0] = 7 - // means continuous capture until frame buffer is full -#define CAP_DONE_MASK 0x08 -#define BURST_FIFO_READ 0x3C // Burst FIFO read operation - -#define ARDUCHIP_FIFO 0x04 // FIFO and I2C control -#define FIFO_CLEAR_MASK 0x01 -#define FIFO_START_MASK 0x02 -#define MAX_FIFO_SIZE 0x7FFFFF // 8MByte - -#define FIFO_SIZE1 0x42 // Camera write FIFO size[7:0] for burst to read -#define FIFO_SIZE2 0x43 // Camera write FIFO size[15:8] -#define FIFO_SIZE3 0x44 // Camera write FIFO size[18:16] +#include + +// Constants + +#define ARDUCAM_DELAY_2MS pdMS_TO_TICKS(2) + +// Arduchip masks +#define ARDUCHIP_WRITE_MASK 0x80 +#define ARDUCAM_RESET_CPLD_MASK 0x80 + +// Arduchip Opcodes +#define OP_READ_TEST_REG 0x00 +#define OP_READ_CAPTURE_CONTROL_REG 0x01 +#define OP_READ_SENSOR_TIMING_CONTROL_REG 0x03 +#define OP_READ_FIFO_CONTROL_REG 0x04 +#define OP_READ_SENSOR_POWER_CONTROL_REG 0x06 +#define OP_RESET_CPLD (0x07 | ARDUCHIP_WRITE_MASK) +#define OP_FIFO_BURST_READ 0x3C +#define OP_FIFO_READ 0x3D +#define OP_READ_FW_VERSION 0x40 +#define OP_READ_CAPTURE_STATUS_REG 0x41 +#define OP_READ_FIFO_SIZE_LOWER 0x42 +#define OP_READ_FIFO_SIZE_MIDDLE 0x43 +#define OP_READ_FIFO_SIZE_UPPER 0x44 +#define OP_WRITE_TEST_REG (OP_READ_TEST_REG | ARDUCHIP_WRITE_MASK) +#define OP_WRITE_CAPTURE_CONTROL_REG (OP_READ_CAPTURE_CONTROL_REG | ARDUCHIP_WRITE_MASK) +#define OP_WRITE_SENSOR_TIMING_CONTROL_REG (OP_READ_SENSOR_TIMING_CONTROL_REG | ARDUCHIP_WRITE_MASK) +#define OP_WRITE_FIFO_CONTROL_REG (OP_READ_FIFO_CONTROL_REG | ARDUCHIP_WRITE_MASK) +#define OP_WRITE_SENSOR_POWER_CONTROL_REG (OP_READ_SENSOR_POWER_CONTROL_REG | ARDUCHIP_WRITE_MASK) // Camera Img Sensor (I2C) defines #define CAM_I2C_ADDR 0x3C - #define I2C_MUTEX_TIMEOUT portMAX_DELAY #define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) -static uint8_t m_fmt; -// Todo: support multiple image captures in different files -static const char fname[] = "image.jpg"; - // SPI values static spiDAT1_t arducamSPIDataFmt = {.CS_HOLD = 0, .CSNR = SPI_CS_NONE, .DFSEL = CAM_SPI_DATA_FORMAT, .WDEL = 0}; -static cam_settings_t cam_config[] = { - [PRIMARY] = {.cs_num = CAM_CS_1}, - [SECONDARY] = {.cs_num = CAM_CS_2}, -}; -void setFormat(image_format_t fmt) { - if (fmt == BMP) - m_fmt = BMP; - else if (fmt == RAW) - m_fmt = RAW; - else - m_fmt = JPEG; -} - -obc_error_code_t initCam(void) { - obc_error_code_t errCode; - // Reset camera - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3008, 0x80)); - vTaskDelay(pdMS_TO_TICKS(2)); - // Setup at 320x420 resolution - RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamConfig(OV5642_QVGA_Preview_Config), PREVIEW_CONFIG_LEN)); - vTaskDelay(pdMS_TO_TICKS(1)); - if (m_fmt == JPEG) { - vTaskDelay(pdMS_TO_TICKS(1)); - // Switch to JPEG capture - RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamConfig(OV5642_JPEG_Capture_QSXGA_Config), JPEG_CONFIG_LEN)); - // Switch to lowest JPEG resolution - RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamConfig(OV5642_320x240_Config), RES_320_240_CONFIG_LEN)); - - vTaskDelay(pdMS_TO_TICKS(1)); - // Vertical flip - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3818, 0xa8)); - // Pixel binning - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3621, 0x10)); - // Image horizontal control - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3801, 0xb0)); - // Image compression - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x4407, 0x04)); - // Lens correction - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x5888, 0x00)); - // Image processor setup - RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x5000, 0xFF)); - } - return errCode; -} +static const uint8_t cameraCS[CAMERA_COUNT] = { + [PRIMARY] = CAM_CS_1, + [SECONDARY] = CAM_CS_2, +}; -obc_error_code_t ov5642SetJpegSize(image_resolution_t size) { +static camera_id_t selectedCamera = PRIMARY; + +typedef enum opcode { + ARDUCAM_READ_TEST_REG, + ARDUCAM_WRITE_TEST_REG, + ARDUCAM_READ_CAPTURE_CONTROL_REG, + ARDUCAM_WRITE_CAPTURE_CONTROL_REG, + ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG, + ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG, + ARDUCAM_READ_FIFO_CONTROL_REG, + ARDUCAM_WRITE_FIFO_CONTROL_REG, + ARDUCAM_READ_SENSOR_POWER_CONTROL_REG, + ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG, + ARDUCAM_FIFO_BURST_READ, + ARDUCAM_FIFO_READ, + ARDUCAM_READ_FW_VERSION, + ARDUCAM_READ_CAPTURE_STATUS_REG, + ARDUCAM_READ_FIFO_SIZE_LOWER, + ARDUCAM_READ_FIFO_SIZE_MIDDLE, + ARDUCAM_READ_FIFO_SIZE_UPPER, + ARDUCAM_RESET_CPLD, +} opcode_t; + +void selectCamera(camera_id_t cameraID) { selectedCamera = cameraID; } + +camera_id_t getSelectedCamera(void) { return selectedCamera; } + +// CS assumed to be asserted +static obc_error_code_t arducamTransmitOpcode(opcode_t opcode) { obc_error_code_t errCode; - switch (size) { - // Todo: all other resolutions are unimplemented - case OV5642_320x240: - RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamConfig(OV5642_320x240_Config), RES_320_240_CONFIG_LEN)); + switch (opcode) { + case ARDUCAM_READ_TEST_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_TEST_REG)); break; - case OV5642_640x480: - // camWriteSensorRegs16_8(ov5642_640x480); + case ARDUCAM_WRITE_TEST_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_TEST_REG)); break; - case OV5642_1024x768: - // camWriteSensorRegs16_8(ov5642_1024x768); + case ARDUCAM_READ_CAPTURE_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_CAPTURE_CONTROL_REG)); break; - case OV5642_1280x960: - // camWriteSensorRegs16_8(ov5642_1280x960); + case ARDUCAM_WRITE_CAPTURE_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_CAPTURE_CONTROL_REG)); break; - case OV5642_1600x1200: - // camWriteSensorRegs16_8(ov5642_1600x1200); + case ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_SENSOR_TIMING_CONTROL_REG)); break; - case OV5642_2048x1536: - // camWriteSensorRegs16_8(ov5642_2048x1536); + case ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_SENSOR_TIMING_CONTROL_REG)); break; - case OV5642_2592x1944: - // camWriteSensorRegs16_8(ov5642_2592x1944); + case ARDUCAM_READ_FIFO_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_CONTROL_REG)); break; - default: - RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamConfig(OV5642_320x240_Config), RES_320_240_CONFIG_LEN)); + case ARDUCAM_WRITE_FIFO_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_FIFO_CONTROL_REG)); + break; + case ARDUCAM_READ_SENSOR_POWER_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_SENSOR_POWER_CONTROL_REG)); + break; + case ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_SENSOR_POWER_CONTROL_REG)); break; + case ARDUCAM_FIFO_BURST_READ: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_FIFO_BURST_READ)); + break; + case ARDUCAM_FIFO_READ: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_FIFO_READ)); + break; + case ARDUCAM_READ_FW_VERSION: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FW_VERSION)); + break; + case ARDUCAM_READ_CAPTURE_STATUS_REG: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_CAPTURE_STATUS_REG)); + break; + case ARDUCAM_READ_FIFO_SIZE_LOWER: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_SIZE_LOWER)); + break; + case ARDUCAM_READ_FIFO_SIZE_MIDDLE: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_SIZE_MIDDLE)); + break; + case ARDUCAM_READ_FIFO_SIZE_UPPER: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_SIZE_UPPER)); + break; + case ARDUCAM_RESET_CPLD: + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_RESET_CPLD)); + break; + default: + LOG_ERROR_CODE(OBC_ERR_CODE_INVALID_ARG); + errCode = OBC_ERR_CODE_INVALID_ARG; } - return OBC_ERR_CODE_SUCCESS; + return errCode; } -obc_error_code_t flushFifo(camera_t cam) { return camWriteReg(ARDUCHIP_FIFO, FIFO_CLEAR_MASK, cam); } +obc_error_code_t arducamReadTestReg(uint8_t *buffer) { + obc_error_code_t errCode; + obc_error_code_t prevCode; -obc_error_code_t startCapture(camera_t cam) { return camWriteReg(ARDUCHIP_FIFO, FIFO_START_MASK, cam); } + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } -obc_error_code_t clearFifoFlag(camera_t cam) { return camWriteReg(ARDUCHIP_FIFO, FIFO_CLEAR_MASK, cam); } + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_TEST_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, buffer)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; -obc_error_code_t setFifoBurst(camera_t cam) { return camWriteByte(BURST_FIFO_READ, cam); } + return errCode; +} + +obc_error_code_t ardcamWriteTestReg(uint8_t value) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_WRITE_TEST_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, value)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + return errCode; +} -obc_error_code_t captureImage(camera_t cam) { +obc_error_code_t arducamReadCaptureControlReg(uint8_t *buffer) { obc_error_code_t errCode; - errCode = flushFifo(cam); - if (!errCode) { - errCode = clearFifoFlag(cam); + obc_error_code_t prevCode; + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; } - if (!errCode) { - errCode = startCapture(cam); + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_CAPTURE_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, buffer)); } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; return errCode; } -bool isCaptureDone(camera_t cam) { return (bool)getBit(ARDUCHIP_TRIG, CAP_DONE_MASK, cam); } +obc_error_code_t arducamWriteCaptureControlReg(uint8_t value) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + if (value > 7) { + return OBC_ERR_CODE_INVALID_ARG; + } -obc_error_code_t readFifoLength(uint32_t *length, camera_t cam) { + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_WRITE_CAPTURE_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, value)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + return errCode; +} + +obc_error_code_t arducamReadSensorTimingControlReg(uint8_t *buffer) { obc_error_code_t errCode; - uint32_t len1 = 0, len2 = 0, len3 = 0; - uint8_t rx_data = 0; + obc_error_code_t prevCode; + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } - RETURN_IF_ERROR_CODE(camReadReg(FIFO_SIZE1, &rx_data, cam)); - len1 = rx_data; - RETURN_IF_ERROR_CODE(camReadReg(FIFO_SIZE2, &rx_data, cam)); - len2 = rx_data; - RETURN_IF_ERROR_CODE(camReadReg(FIFO_SIZE3, &rx_data, cam)); - len3 = (rx_data & 0x7f); + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, buffer)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; - *length = ((len3 << 16) | (len2 << 8) | len1) & 0x07fffff; return errCode; } -obc_error_code_t readFifoBurst(camera_t cam) { +obc_error_code_t arducamWriteSensorTimingControlReg(uint8_t value) { obc_error_code_t errCode; - int32_t file = 0; - uint32_t length = 0; - uint8_t temp = 0, temp_last = 0; - bool is_header = false; - - // Open a new image file - RETURN_IF_ERROR_CODE(createFile(fname, &file)); - - readFifoLength(&length, cam); - if (length >= MAX_FIFO_SIZE) { - // 512 kb - errCode = OBC_ERR_CODE_FRAME_SIZE_OUT_OF_RANGE; - } else if (length == 0) { - // 0 kb - errCode = OBC_ERR_CODE_FRAME_SIZE_OUT_OF_RANGE; - } - - RETURN_IF_ERROR_CODE(errCode); - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, 1)); - - // Set fifo to burst mode, receive continuous data until EOF - errCode = setFifoBurst(cam); - camReadByte(&temp, cam); - length--; - while (length-- && !errCode) { - temp_last = temp; - errCode = camReadByte(&temp, cam); - if (!errCode) { - if (is_header == true) { - errCode = writeFile(file, &temp, 1); - } else if ((temp == 0xD8) & (temp_last == 0xFF)) { - is_header = true; - errCode = writeFile(file, &temp_last, 1); - if (!errCode) { - errCode = writeFile(file, &temp, 1); - } - } - if ((temp == 0xD9) && (temp_last == 0xFF)) { - break; - } - } + obc_error_code_t prevCode; - // Todo: Can this be changed to ~15us instead? - vTaskDelay(pdMS_TO_TICKS(1)); + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, value)); } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; - if (!errCode) { - errCode = deassertChipSelect(CAM_SPI_PORT, 1); - } else { - // If there was an error during capture, deassert without an error check - deassertChipSelect(CAM_SPI_PORT, 1); + return errCode; +} + +obc_error_code_t arducamReadFIFOControlReg(uint8_t *buffer) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; } - if (!errCode) { - errCode = closeFile(file); + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_FIFO_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, buffer)); } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; return errCode; } -uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam) { - uint8_t temp; - camReadReg(addr, &temp, cam); - temp = temp & bit; - return temp; +obc_error_code_t arducamWriteFIFOControlReg(uint8_t value) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_WRITE_FIFO_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, value)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + return errCode; } -obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam) { +obc_error_code_t arducamReadSensorPowerControlReg(uint8_t *buffer) { obc_error_code_t errCode; - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - addr = addr | 0x80; - uint8_t tx[2] = {addr, data}; - errCode = spiTransmitBytes(CAM_SPI_REG, &arducamSPIDataFmt, tx, 2); - RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + obc_error_code_t prevCode; + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_SENSOR_POWER_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, buffer)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + return errCode; +} + +obc_error_code_t arducamWriteSensorPowerControlReg(uint8_t value) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, value)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + return errCode; +} + +obc_error_code_t arducamReadFIFO(uint8_t *buffer) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_FIFO_READ)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, buffer)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + return errCode; +} + +obc_error_code_t arducamBurstReadFIFO(uint8_t *buffer, size_t bufferSize) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + + if (buffer == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_FIFO_BURST_READ)); + for (size_t index = 0; (index < bufferSize) && (errCode == OBC_ERR_CODE_SUCCESS); index++) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, &buffer[index])); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + return errCode; } -obc_error_code_t camReadReg(uint8_t addr, uint8_t *rx_data, camera_t cam) { +obc_error_code_t arducamReadFWVersion(uint8_t *version) { obc_error_code_t errCode; - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - addr = addr & 0x7F; - errCode = spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, addr); - if (!errCode) { - errCode = spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, rx_data); + obc_error_code_t prevCode; + if (version == NULL) { + return OBC_ERR_CODE_INVALID_ARG; } - RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_FW_VERSION)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, version)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; return errCode; } -obc_error_code_t camWriteByte(uint8_t byte, camera_t cam) { +obc_error_code_t arducamReadCaptureStatusReg(uint8_t *status) { obc_error_code_t errCode; - // RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); - errCode = spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, byte); - // RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + obc_error_code_t prevCode; + if (status == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_CAPTURE_STATUS_REG)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, status)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; return errCode; } -obc_error_code_t camReadByte(uint8_t *byte, camera_t cam) { - return spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, byte); +obc_error_code_t arducamReadFIFOSize(uint32_t *fifoSize) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + uint8_t upper = 0; + uint8_t middle = 0; + uint8_t lower = 0; + if (fifoSize == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + + *fifoSize = 0; + + // Get upper bits + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_FIFO_SIZE_UPPER)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, &upper)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + + // Get middle bits + if (errCode == OBC_ERR_CODE_SUCCESS) { + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_FIFO_SIZE_MIDDLE)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, &middle)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + } + + // Get lower bits + if (errCode == OBC_ERR_CODE_SUCCESS) { + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_READ_FIFO_SIZE_LOWER)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiReceiveByte(CAM_SPI_REG, &arducamSPIDataFmt, &lower)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + } + + *fifoSize = upper; + *fifoSize = (*fifoSize << 8) | middle; + *fifoSize = (*fifoSize << 8) | lower; + + return errCode; +} + +obc_error_code_t resetCPLD(void) { + obc_error_code_t errCode; + obc_error_code_t prevCode; + + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_RESET_CPLD)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_RESET_CPLD_MASK)); + } + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + // Reset overwritten error code + errCode = prevCode; + if (errCode == OBC_ERR_CODE_SUCCESS) { + vTaskDelay(pdMS_TO_TICKS(2)); + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_RESET_CPLD)); + if (errCode == OBC_ERR_CODE_SUCCESS) { + LOG_IF_ERROR_CODE( + spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, (ARDUCAM_RESET_CPLD_MASK & (~ARDUCAM_RESET_CPLD_MASK)))); + } + // Reset overwritten error code + prevCode = errCode; + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); + } + + return errCode; } obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat) { diff --git a/obc/drivers/arducam/arducam.h b/obc/drivers/arducam/arducam.h index 51b5cd718..1a16f6a0e 100644 --- a/obc/drivers/arducam/arducam.h +++ b/obc/drivers/arducam/arducam.h @@ -10,125 +10,204 @@ #include "ov5642_reg.h" #include "obc_board_config.h" +// Arduchip Constants +#define MAX_FIFO_SIZE 0x7FFFFF // 8MByte + +// Sensor Timing Control Masks +#define HSYNC_ACTIVE_LOW_MASK (0x01U << 0) +#define VSYNC_ACTIVE_LOW_MASK (0x01U << 1) +#define PCLK_REVERSED_MASK (0x01U << 3) +// FIFO Control Masks +#define FIFO_CLEAR_CAPTURE_DONE_FLAG (0x01U << 0) +#define FIFO_START_CAPTURE (0x01U << 1) +#define FIFO_RESET_WRITE_PTR (0x01U << 4) +#define FIFO_RESET_READ_PTR (0x01U << 5) +// Sensor Control Masks +#define SENSOR_RESET_MASK (0x01U << 0) +#define SENSOR_STANDBY_MASK (0x01 << 1) +#define SENSOR_POWER_EN_MASK (0x01U << 2) +// Capture Status Masks +#define STATUS_VSYNC_MASK (0x01U << 0) +#define STATUS_CAPTURE_DONE_MASK (0x01 << 3) + /** * @enum camera_t * @brief Primary or secondary camera. * - * Enum containing camera identifiers. + * Enum containing camera identifiers and camera count. */ -typedef enum { PRIMARY, SECONDARY } camera_t; +typedef enum { + PRIMARY, + SECONDARY, + CAMERA_COUNT, +} camera_id_t; /** - * @enum image_format_t - * @brief OV5642 supported image formats. + * @brief Selects one of the camera. * - * Enum containing all supported image formats. + * @param cameraID Camera ID of the camera to be selected. */ -typedef enum { BMP, JPEG, RAW } image_format_t; +void selectCamera(camera_id_t cameraID); /** - * @enum image_resolution_t - * @brief OV5642 supported image resolutions. + * @brief Returns the camera id of the selected camera. * - * Enum containing all supported image resolutions. + * @return Camera ID of the selected camera. */ -typedef enum { - OV5642_320x240, - OV5642_640x480, - OV5642_1024x768, - OV5642_1280x960, - OV5642_1600x1200, - OV5642_2048x1536, - OV5642_2592x1944, - OV5642_1920x1080, -} image_resolution_t; +camera_id_t getSelectedCamera(void); + +/** + * @brief Resets arducam chip. Needed for some ARM architecture for SPI to work. IDK why this is not in the docs >:( + * https://docs.arducam.com/Arduino-SPI-camera/Legacy-SPI-camera/FAQ/ + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ + +obc_error_code_t resetCPLD(void); + +/** + * @brief Read Arducam's Test Register + * + * @param buffer 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t arducamReadTestReg(uint8_t* buffer); + +/** + * @brief Write a value to Arducam's Test Register + * + * @param value 1 byte value to be written. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t ardcamWriteTestReg(uint8_t value); /** - * @brief Set format to JPEG, BMP, or RAW - * @param fmt The image format to set + * @brief Read Arducam's Capture Control Register + * Value determines number of frames captured. + * 0 -> 6 = 1 -> 7 frames captured; 7 = keep capturing + * until FIFO is full. + * @param buffer 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -void setFormat(image_format_t fmt); +obc_error_code_t arducamReadCaptureControlReg(uint8_t* buffer); /** - * @brief Initialize camera selected by tcaSelect() + * @brief Write a value to Arducam's Capture Control Register + * Value determines number of frames captured. + * 0 -> 6 = 1 -> 7 frames captured; 7 = keep capturing + * until FIFO is full. + * @param value 1 byte value to be written. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t initCam(void); +obc_error_code_t arducamWriteCaptureControlReg(uint8_t value); /** - * @brief Change JPEG resolution - * @param size The JPEG resolution to set + * @brief Read Arducam's Sensor Timing Control Register + * Bit[0] Hsync Polarity: 0 = Active High, 1 = Active Low; + * Bit[1] Vsync Polarity: 0 = Active High, 1 = Active Low; + * Bit[3] Sensor PCLK reverse: 0 = normal, 1 = reversed PCLK + * @param buffer 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t ov5642SetJpegSize(image_resolution_t size); +obc_error_code_t arducamReadSensorTimingControlReg(uint8_t* buffer); /** - * @brief Trigger an image capture - * @param cam The camera to trigger a capture on + * @brief Write a value to Arducam's Sensor Timing Control Register + * Bit[0] Hsync Polarity: 0 = Active High, 1 = Active Low; + * Bit[1] Vsync Polarity: 0 = Active High, 1 = Active Low; + * Bit[3] Sensor PCLK reverse: 0 = normal, 1 = reversed PCLK + * @param value 1 byte value to be written. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t captureImage(camera_t cam); +obc_error_code_t arducamWriteSensorTimingControlReg(uint8_t value); /** - * @brief Read back image data - * @param cam The camera to read from + * @brief Read Arducam's FIFO Control Register + * Bit[0]: clear FIFO write/capture done flag; + * Bit[1]: start capture; + * Bit[4]: reset FIFO write pointer; + * Bit[5]: reset FIFO read pointer + * @param buffer 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t readFifoBurst(camera_t cam); +obc_error_code_t arducamReadFIFOControlReg(uint8_t* buffer); /** - * @brief Checks if image capture has been completed - * @param cam The camera to check - * @return Returns true if capture is complete + * @brief Write a value to Arducam's FIFO Control Register + * Write 1 to following bits to + * Bit[0]: clear FIFO write/capture done flag; + * Bit[1]: start capture; + * Bit[4]: reset FIFO write pointer; + * Bit[5]: reset FIFO read pointer + * @param value 1 byte value to be written. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -bool isCaptureDone(camera_t cam); +obc_error_code_t arducamWriteFIFOControlReg(uint8_t value); /** - * @brief Reads length of image in FIFO - * @param length pointer to uint32_t to store value - * @param cam The camera to check + * @brief Read Arducam's Sensor Power Control Register + * Bit[0]: Reset Sensor? + * Bit[1]: Standby Sensor 0 = out of standby, 1 = in standby; + * Bit[2]: Power Down Sensor 0 = disable power, 1 = enable power; + * Note: After Power Down, Sensor will need to be reinitialized + * @param buffer 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + * @return obc_error_code_t */ -obc_error_code_t readFifoLength(uint32_t* length, camera_t cam); +obc_error_code_t arducamReadSensorPowerControlReg(uint8_t* buffer); /** - * @struct camera_settings_t - * @brief Camera settings struct + * @brief Write a value to Arducam's Sensor Power Control Register + * Bit[0]: Reset Sensor: 0 = reset sensor, 1 = out of reset; + * Bit[1]: Standby Sensor 0 = out of standby, 1 = in standby; + * Bit[2]: Power Down Sensor 0 = disable power, 1 = enable power; + * Note: After Power Down, Sensor will need to be reinitialized + * @param value 1 byte value to be written. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t arducamWriteSensorPowerControlReg(uint8_t value); + +/** + * @brief Read a byte from the Arducam FIFO * - * Holds the settings for each camera. + * @param buffer 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -typedef struct { - uint8_t cs_num; -} cam_settings_t; +obc_error_code_t arducamReadFIFO(uint8_t* buffer); /** - * @brief Write to a camera register over SPI - * @param addr Register address to write to - * @param data Data to send - * @param cam Camera identifier - * @return Error code indicating if the write was successful + * @brief Read bufferSize bytes from the Arducam FIFO + * + * @param buffer bufferSize byte buffer to store value read. + * @param bufferSize size of buffer. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam); +obc_error_code_t arducamBurstReadFIFO(uint8_t* buffer, size_t bufferSize); /** - * @brief Read a camera register over SPI - * @param addr Register address to read from - * @param rx_data Buffer to store received data - * @param cam Camera identifier - * @return Error code indicating if the read was successful + * @brief Read Arducam's arduchip firmware verion. + * Interpreted as Bits[7:4] . Bits[3:0] + * @param version 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t camReadReg(uint8_t regID, uint8_t* regDat, camera_t cam); +obc_error_code_t arducamReadFWVersion(uint8_t* version); /** - * @brief Write one byte to a camera over SPI - * @param byte Camera settings struct - * @param cam Camera identifier - * @return Error code + * @brief Read Arducam's capture status. + * Bit[0] : vsync pin realtime status; + * Bit[3] : capture done flag + * @param version 1 byte buffer to store value read. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t camWriteByte(uint8_t byte, camera_t cam); +obc_error_code_t arducamReadCaptureStatusReg(uint8_t* status); /** - * @brief Read one byte to a camera over SPI, does not handle CS assertion - * @param byte Camera settings struct - * @param cam Camera identifier - * @return Error code + * @brief Read the size of the Write FIFO + * + * @param fifoSize uint32_t buffer to store value + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t camReadByte(uint8_t* byte, camera_t cam); +obc_error_code_t arducamReadFIFOSize(uint32_t* fifoSize); /** * @brief Read 8 bits from a 16 bit register over I2C @@ -152,10 +231,3 @@ obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t* regDat); * @return Error code indicating if the writes were successful */ obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen); - -/** - * @brief Read one bit from a register over SPI - * @param addr Address to read from - * @param bit Bit to read - */ -uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam); diff --git a/obc/drivers/arducam/ov5642_reg.c b/obc/drivers/arducam/ov5642_reg.c index e972ae75d..3a781d837 100644 --- a/obc/drivers/arducam/ov5642_reg.c +++ b/obc/drivers/arducam/ov5642_reg.c @@ -179,15 +179,8 @@ static sensor_reg_t OV5642_320x240[RES_320_240_CONFIG_LEN] = { {0x5684, 0x0}, {0x5685, 0x0}, {0x5686, 0x7}, {0x5687, 0x98}, {0x3801, 0xb0}, {0xffff, 0xff}, }; -sensor_reg_t* getCamConfig(cam_config_t config) { - switch (config) { - case OV5642_QVGA_Preview_Config: - return OV5642_QVGA_Preview; - case OV5642_JPEG_Capture_QSXGA_Config: - return OV5642_JPEG_Capture_QSXGA; - case OV5642_320x240_Config: - return OV5642_320x240; - default: - return NULL; // Invalid Config - } -} +sensor_reg_t* getCamPreviewConfig(void) { return OV5642_QVGA_Preview; } + +sensor_reg_t* getCamCaptureConfig(void) { return OV5642_JPEG_Capture_QSXGA; } + +sensor_reg_t* getCamResolutionConfig(void) { return OV5642_320x240; } diff --git a/obc/drivers/arducam/ov5642_reg.h b/obc/drivers/arducam/ov5642_reg.h index 9c6942bd7..e291e7321 100644 --- a/obc/drivers/arducam/ov5642_reg.h +++ b/obc/drivers/arducam/ov5642_reg.h @@ -14,18 +14,22 @@ typedef struct { uint16_t reg; uint8_t val; } sensor_reg_t; - /** - * @enum cam_config_t - * @brief Configuration array names to be called with getCamConfig(). - * - * Configuration array names. + * @brief Access camera preview configuration arrays + * @param config Camera config array name + * @return Pointer to config array */ -typedef enum { OV5642_QVGA_Preview_Config, OV5642_JPEG_Capture_QSXGA_Config, OV5642_320x240_Config } cam_config_t; +sensor_reg_t* getCamPreviewConfig(void); /** - * @brief Access camera configuration arrays + * @brief Access camera capture configuration arrays + * @param config Camera config array name + * @return Pointer to config array + */ +sensor_reg_t* getCamCaptureConfig(void); +/** + * @brief Access camera resolution configuration arrays * @param config Camera config array name * @return Pointer to config array */ -sensor_reg_t* getCamConfig(cam_config_t config); +sensor_reg_t* getCamResolutionConfig(void); diff --git a/obc/drivers/arducam/tca.c b/obc/drivers/tca9458a/tca9458a.c similarity index 63% rename from obc/drivers/arducam/tca.c rename to obc/drivers/tca9458a/tca9458a.c index 7a330855e..ad112c26d 100644 --- a/obc/drivers/arducam/tca.c +++ b/obc/drivers/tca9458a/tca9458a.c @@ -6,23 +6,18 @@ #include "obc_logging.h" #include "obc_board_config.h" -#include "ov5642_reg.h" -#include "camera_reg.h" - -#define CAM_I2C_WR_ADDR 0x3C -#define CAM_I2C_RD_ADDR 0x3C - #define TCA_I2C_ADDR 0x70 #define I2C_MUTEX_TIMEOUT portMAX_DELAY #define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) -obc_error_code_t tcaSelect(camera_t cam) { +// TODO: Fully develop and test this driver + +obc_error_code_t tcaSelect(uint8_t portNum) { uint8_t tca = 0; - if (cam == PRIMARY) { - tca = (1 << 0); - } else { - tca = (1 << 1); + if (portNum > 7) { + return OBC_ERR_CODE_INVALID_ARG; } + tca = 1 << portNum; return i2cSendTo(TCA_I2C_ADDR, 1, &tca, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); } diff --git a/obc/drivers/arducam/tca.h b/obc/drivers/tca9458a/tca9458a.h similarity index 86% rename from obc/drivers/arducam/tca.h rename to obc/drivers/tca9458a/tca9458a.h index d4754efce..fbad0bddf 100644 --- a/obc/drivers/arducam/tca.h +++ b/obc/drivers/tca9458a/tca9458a.h @@ -10,4 +10,4 @@ * @param tca Port number to select * @return Error code indicating if an ACK was received */ -obc_error_code_t tcaSelect(camera_t cam); +obc_error_code_t tcaSelect(uint8_t cam); diff --git a/obc/examples/test_app_arducam/main.c b/obc/examples/test_app_arducam/main.c index db85b810f..1c03350b8 100644 --- a/obc/examples/test_app_arducam/main.c +++ b/obc/examples/test_app_arducam/main.c @@ -74,7 +74,7 @@ void vTask1(void *pvParameters) { sciPrintf("Read %d from test reg\r\n", byte); setFormat(JPEG); initCam(); - camWriteReg(0x03, 0x02, PRIMARY); + // camWriteReg(0x03, 0x02, PRIMARY); // camWriteSensorReg16_8(0x503d , 0x80); // camWriteSensorReg16_8(0x503e, 0x00); ov5642SetJpegSize(OV5642_320x240); diff --git a/obc/modules/CMakeLists.txt b/obc/modules/CMakeLists.txt index a00032a2c..97a9f2075 100644 --- a/obc/modules/CMakeLists.txt +++ b/obc/modules/CMakeLists.txt @@ -22,6 +22,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/alarm_mgr/alarm_handler.c ${CMAKE_CURRENT_SOURCE_DIR}/camera_mgr/payload_manager.c + ${CMAKE_CURRENT_SOURCE_DIR}/camera_mgr/camera_control.c ${CMAKE_CURRENT_SOURCE_DIR}/command_mgr/command_manager.c ${CMAKE_CURRENT_SOURCE_DIR}/command_mgr/command_callbacks.c diff --git a/obc/modules/camera_mgr/camera_control.c b/obc/modules/camera_mgr/camera_control.c new file mode 100644 index 000000000..e4bd66663 --- /dev/null +++ b/obc/modules/camera_mgr/camera_control.c @@ -0,0 +1,58 @@ +#include "camera_control.h" + +static uint32_t totalBytesToRead[CAMERA_COUNT] = {0}; +static uint32_t FIFOReadPtr[CAMERA_COUNT] = {0}; + +size_t bytesLeftInFIFO(void) { + camera_id_t selectedCamera = getSelectedCamera(); + return (totalBytesToRead[selectedCamera] < FIFOReadPtr[selectedCamera]) + ? 0 + : totalBytesToRead[selectedCamera] - FIFOReadPtr[selectedCamera]; +} + +obc_error_code_t initCamera(void) { + obc_error_code_t errCode; + memset(totalBytesToRead, 0, sizeof(size_t) * CAMERA_COUNT); + memset(FIFOReadPtr, 0, sizeof(size_t) * CAMERA_COUNT); + RETURN_IF_ERROR_CODE(resetCPLD()); + RETURN_IF_ERROR_CODE(arducamWriteSensorTimingControlReg(VSYNC_ACTIVE_LOW_MASK)); + return OBC_ERR_CODE_SUCCESS; +} + +bool isCaptureDone(void) { + obc_error_code_t errCode; + uint8_t status; + LOG_IF_ERROR_CODE(arducamReadCaptureStatusReg(&status)); + return (errCode == OBC_ERR_CODE_SUCCESS) ? (bool)(status & STATUS_CAPTURE_DONE_MASK) : true; +} + +obc_error_code_t camConfigureSensor(void) { + obc_error_code_t errCode; + // Reset camera + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3008, 0x80)); + // Setup at 320x420 resolution + RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamPreviewConfig(), PREVIEW_CONFIG_LEN)); + vTaskDelay(pdMS_TO_TICKS(1)); + + vTaskDelay(pdMS_TO_TICKS(1)); + // Switch to JPEG capture + RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamCaptureConfig(), JPEG_CONFIG_LEN)); + // Switch to lowest JPEG resolution + RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamResolutionConfig(), RES_320_240_CONFIG_LEN)); + + vTaskDelay(pdMS_TO_TICKS(1)); + // Vertical flip + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3818, 0xa8)); + // Pixel binning + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3621, 0x10)); + // Image horizontal control + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3801, 0xb0)); + // Image compression + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x4407, 0x08)); + // Lens correction + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x5888, 0x00)); + // Image processor setup + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x5000, 0xFF)); + + return errCode; +} diff --git a/obc/modules/camera_mgr/camera_control.h b/obc/modules/camera_mgr/camera_control.h new file mode 100644 index 000000000..482f3d503 --- /dev/null +++ b/obc/modules/camera_mgr/camera_control.h @@ -0,0 +1,23 @@ +#include "arducam.h" + +/** + * @brief Returns number of Bytes left in FIFO to read + * + * @return number of bytes + */ +size_t bytesLeftInFIFO(void); + +/** + * @brief Initialize selected camera. + */ +obc_error_code_t initCamera(void); + +/** + * @brief Returns status of capture. + * @note Will return true if errors occur. Capture is done, just incorrectly. + * + * @return true if capture is done. + */ +bool isCaptureDone(void); + +obc_error_code_t camConfigureSensor(void); diff --git a/obc/drivers/arducam/image_processing.c b/obc/modules/camera_mgr/image_processing.c similarity index 100% rename from obc/drivers/arducam/image_processing.c rename to obc/modules/camera_mgr/image_processing.c diff --git a/obc/drivers/arducam/image_processing.h b/obc/modules/camera_mgr/image_processing.h similarity index 100% rename from obc/drivers/arducam/image_processing.h rename to obc/modules/camera_mgr/image_processing.h From 6ccc91357a7d56e4a61c53877e0916be549e3c20 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Mon, 1 Apr 2024 19:19:30 -0400 Subject: [PATCH 04/18] Added more camera control helper functions; Added new error for camera capture; renamed ov5642_reg files to config ov5642_config files --- obc/drivers/CMakeLists.txt | 2 +- obc/drivers/arducam/arducam.c | 6 +- obc/drivers/arducam/arducam.h | 6 +- .../arducam/{ov5642_reg.c => ov5642_config.c} | 14 +-- .../arducam/{ov5642_reg.h => ov5642_config.h} | 13 ++- obc/examples/test_app_arducam/main.c | 99 +++++++--------- obc/modules/camera_mgr/camera_control.c | 106 ++++++++++++++++-- obc/modules/camera_mgr/camera_control.h | 72 +++++++++++- obc/sys/obc_errors.h | 2 +- 9 files changed, 224 insertions(+), 96 deletions(-) rename obc/drivers/arducam/{ov5642_reg.c => ov5642_config.c} (97%) rename obc/drivers/arducam/{ov5642_reg.h => ov5642_config.h} (68%) diff --git a/obc/drivers/CMakeLists.txt b/obc/drivers/CMakeLists.txt index 0382cba16..dae0a4e3d 100644 --- a/obc/drivers/CMakeLists.txt +++ b/obc/drivers/CMakeLists.txt @@ -31,7 +31,7 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/rm46/obc_dma.c ${CMAKE_CURRENT_SOURCE_DIR}/arducam/arducam.c - ${CMAKE_CURRENT_SOURCE_DIR}/arducam/ov5642_reg.c + ${CMAKE_CURRENT_SOURCE_DIR}/arducam/ov5642_config.c ${CMAKE_CURRENT_SOURCE_DIR}/cc1120/cc1120_mcu.c ${CMAKE_CURRENT_SOURCE_DIR}/cc1120/cc1120.c diff --git a/obc/drivers/arducam/arducam.c b/obc/drivers/arducam/arducam.c index f05dbffb8..634f4c6a2 100644 --- a/obc/drivers/arducam/arducam.c +++ b/obc/drivers/arducam/arducam.c @@ -1,5 +1,5 @@ #include "arducam.h" -#include "ov5642_reg.h" +#include "ov5642_config.h" #include "obc_i2c_io.h" #include "obc_spi_io.h" @@ -168,7 +168,7 @@ obc_error_code_t arducamReadTestReg(uint8_t *buffer) { return errCode; } -obc_error_code_t ardcamWriteTestReg(uint8_t value) { +obc_error_code_t arducamWriteTestReg(uint8_t value) { obc_error_code_t errCode; obc_error_code_t prevCode; @@ -511,7 +511,7 @@ obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t *regDat) { return errCode; } -obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen) { +obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], uint16_t reglistLen) { obc_error_code_t errCode; for (int i = 0; i < reglistLen; i++) { diff --git a/obc/drivers/arducam/arducam.h b/obc/drivers/arducam/arducam.h index 1a16f6a0e..ada05ad00 100644 --- a/obc/drivers/arducam/arducam.h +++ b/obc/drivers/arducam/arducam.h @@ -7,7 +7,7 @@ #include "obc_logging.h" #include "obc_spi_io.h" -#include "ov5642_reg.h" +#include "ov5642_config.h" #include "obc_board_config.h" // Arduchip Constants @@ -79,7 +79,7 @@ obc_error_code_t arducamReadTestReg(uint8_t* buffer); * @param value 1 byte value to be written. * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t ardcamWriteTestReg(uint8_t value); +obc_error_code_t arducamWriteTestReg(uint8_t value); /** * @brief Read Arducam's Capture Control Register @@ -230,4 +230,4 @@ obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t* regDat); * @param reglist List of registers and data to write * @return Error code indicating if the writes were successful */ -obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen); +obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], uint16_t reglistLen); diff --git a/obc/drivers/arducam/ov5642_reg.c b/obc/drivers/arducam/ov5642_config.c similarity index 97% rename from obc/drivers/arducam/ov5642_reg.c rename to obc/drivers/arducam/ov5642_config.c index 3a781d837..ed895cb3f 100644 --- a/obc/drivers/arducam/ov5642_reg.c +++ b/obc/drivers/arducam/ov5642_config.c @@ -1,8 +1,8 @@ #include -#include "ov5642_reg.h" +#include "ov5642_config.h" // Configuration for the host preview -static sensor_reg_t OV5642_QVGA_Preview[PREVIEW_CONFIG_LEN] = { +static sensor_config_t OV5642_QVGA_Preview[PREVIEW_CONFIG_LEN] = { {0x3103, 0x93}, {0x3008, 0x82}, {0x3017, 0x7f}, {0x3018, 0xfc}, {0x3810, 0xc2}, {0x3615, 0xf0}, {0x3000, 0x00}, {0x3001, 0x00}, {0x3002, 0x5c}, {0x3003, 0x00}, {0x3004, 0xff}, {0x3005, 0xff}, {0x3006, 0x43}, {0x3007, 0x37}, {0x3011, 0x08}, {0x3010, 0x10}, {0x460c, 0x22}, {0x3815, 0x04}, {0x370c, 0xa0}, {0x3602, 0xfc}, {0x3612, 0xff}, @@ -100,7 +100,7 @@ static sensor_reg_t OV5642_QVGA_Preview[PREVIEW_CONFIG_LEN] = { }; // Switch to JPEG -static sensor_reg_t OV5642_JPEG_Capture_QSXGA[JPEG_CONFIG_LEN] = { +static sensor_config_t OV5642_JPEG_Capture_QSXGA[JPEG_CONFIG_LEN] = { // OV5642_ QSXGA _YUV7.5 fps // 24 MHz input clock, 24Mhz pclk // jpeg mode 7.5fps @@ -172,15 +172,15 @@ static sensor_reg_t OV5642_JPEG_Capture_QSXGA[JPEG_CONFIG_LEN] = { }; // Switch to lowest resolution -static sensor_reg_t OV5642_320x240[RES_320_240_CONFIG_LEN] = { +static sensor_config_t OV5642_320x240[RES_320_240_CONFIG_LEN] = { {0x3800, 0x1}, {0x3801, 0xa8}, {0x3802, 0x0}, {0x3803, 0xA}, {0x3804, 0xA}, {0x3805, 0x20}, {0x3806, 0x7}, {0x3807, 0x98}, {0x3808, 0x1}, {0x3809, 0x40}, {0x380a, 0x0}, {0x380b, 0xF0}, {0x380c, 0xc}, {0x380d, 0x80}, {0x380e, 0x7}, {0x380f, 0xd0}, {0x5001, 0x7f}, {0x5680, 0x0}, {0x5681, 0x0}, {0x5682, 0xA}, {0x5683, 0x20}, {0x5684, 0x0}, {0x5685, 0x0}, {0x5686, 0x7}, {0x5687, 0x98}, {0x3801, 0xb0}, {0xffff, 0xff}, }; -sensor_reg_t* getCamPreviewConfig(void) { return OV5642_QVGA_Preview; } +sensor_config_t* getCamPreviewConfig(void) { return OV5642_QVGA_Preview; } -sensor_reg_t* getCamCaptureConfig(void) { return OV5642_JPEG_Capture_QSXGA; } +sensor_config_t* getCamCaptureConfig(void) { return OV5642_JPEG_Capture_QSXGA; } -sensor_reg_t* getCamResolutionConfig(void) { return OV5642_320x240; } +sensor_config_t* getCamResolutionConfig(void) { return OV5642_320x240; } diff --git a/obc/drivers/arducam/ov5642_reg.h b/obc/drivers/arducam/ov5642_config.h similarity index 68% rename from obc/drivers/arducam/ov5642_reg.h rename to obc/drivers/arducam/ov5642_config.h index e291e7321..9bfda1b90 100644 --- a/obc/drivers/arducam/ov5642_reg.h +++ b/obc/drivers/arducam/ov5642_config.h @@ -7,29 +7,30 @@ #define RES_320_240_CONFIG_LEN 27 /** - * @struct sensor_reg_t - * @brief Sensor reg struct, reg is the address to write to and val is the value to write + * @struct sensor_config_t + * @brief Sensor config struct, reg is the address to write config to and val is the value to write */ typedef struct { uint16_t reg; uint8_t val; -} sensor_reg_t; +} sensor_config_t; + /** * @brief Access camera preview configuration arrays * @param config Camera config array name * @return Pointer to config array */ -sensor_reg_t* getCamPreviewConfig(void); +sensor_config_t* getCamPreviewConfig(void); /** * @brief Access camera capture configuration arrays * @param config Camera config array name * @return Pointer to config array */ -sensor_reg_t* getCamCaptureConfig(void); +sensor_config_t* getCamCaptureConfig(void); /** * @brief Access camera resolution configuration arrays * @param config Camera config array name * @return Pointer to config array */ -sensor_reg_t* getCamResolutionConfig(void); +sensor_config_t* getCamResolutionConfig(void); diff --git a/obc/examples/test_app_arducam/main.c b/obc/examples/test_app_arducam/main.c index 1c03350b8..6f47d568f 100644 --- a/obc/examples/test_app_arducam/main.c +++ b/obc/examples/test_app_arducam/main.c @@ -6,7 +6,7 @@ #include "obc_print.h" #include "arducam.h" -#include "camera_reg.h" +#include "camera_control.h" #include #include @@ -17,87 +17,64 @@ #include #define UART_MUTEX_BLOCK_TIME portMAX_DELAY +#define BUFFER_SIZE 512U -obc_error_code_t readFifoBurst2(uint32_t length) { - obc_error_code_t errCode; - uint8_t temp = 0, temp_last = 0; - - RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, 1)); - - // Set fifo to burst mode, receive continuous data until EOF - errCode = camWriteByte(0x3C, PRIMARY); - while (length-- && !errCode) { - temp_last = temp; - errCode = camReadByte(&temp, PRIMARY); - sciPrintf("0x%X,", temp); - if ((temp == 0xD9) && (temp_last == 0xFF)) { - break; - } - if (length % 30 == 0) { - sciPrintf("\r\n", temp); - } - // // Todo: Can this be changed to ~15us instead? - // vTaskDelay(pdMS_TO_TICKS(1)); - } - - if (!errCode) { - errCode = deassertChipSelect(CAM_SPI_PORT, 1); - } else { - // If there was an error during capture, deassert without an error check - deassertChipSelect(CAM_SPI_PORT, 1); - } - - return errCode; -} - +#define TASK_STACK_SIZE 2048U static StaticTask_t taskBuffer; -static StackType_t taskStack[1024]; +static StackType_t taskStack[TASK_STACK_SIZE]; void vTask1(void *pvParameters) { sciPrintf("Starting Arducam Demo\r\n"); - // Read Camera ID + selectCamera(PRIMARY); + initCamera(); + uint8_t temp; + arducamReadSensorPowerControlReg(&temp); + sciPrintf("Power Control Reg:0x%X\r\n", temp); + + // Read Camera Sensor ID uint8_t cam_id[2] = {0}; camReadSensorReg16_8(0x300A, &cam_id[0]); camReadSensorReg16_8(0x300B, &cam_id[1]); sciPrintf("Sensor ID: %X%X\r\n", cam_id[0], cam_id[1]); - camWriteReg(0x07, 0x80, PRIMARY); - vTaskDelay(pdMS_TO_TICKS(2)); - camWriteReg(0x07, 0x00, PRIMARY); - vTaskDelay(pdMS_TO_TICKS(2)); + + // Test Reg operations uint8_t byte = 0x55; sciPrintf("Writing %d to test reg\r\n", byte); - camWriteReg(0x00, byte, PRIMARY); + arducamWriteTestReg(byte); byte = 0; - camReadReg(0x00, &byte, PRIMARY); - sciPrintf("Read %d from test reg\r\n", byte); - camReadReg(0x00, &byte, PRIMARY); + arducamReadTestReg(&byte); sciPrintf("Read %d from test reg\r\n", byte); - setFormat(JPEG); - initCam(); - // camWriteReg(0x03, 0x02, PRIMARY); - // camWriteSensorReg16_8(0x503d , 0x80); - // camWriteSensorReg16_8(0x503e, 0x00); - ov5642SetJpegSize(OV5642_320x240); - vTaskDelay(pdMS_TO_TICKS(2)); + // Camera Configuration + sciPrintf("Configuring Camera\r\n"); + camConfigureSensor(); + + // Capture sciPrintf("Starting Image Capture\r\n"); - captureImage(PRIMARY); - while (!isCaptureDone(PRIMARY)) + startImageCapture(); + while (!isCaptureDone()) ; sciPrintf("Image Capture Done ^_^\r\n"); + // Read image size uint32_t img_len = 0; - readFifoLength(&img_len, PRIMARY); + arducamReadFIFOSize(&img_len); sciPrintf("image len: %d \r\n", img_len); - uint32_t first_half = img_len / 2; - uint32_t second_half = img_len - first_half; - - readFifoBurst2(first_half); - readFifoLength(&img_len, PRIMARY); - sciPrintf("image len: %d \r\n", img_len); - readFifoBurst2(second_half); + // Read image from FIFO + uint8_t imgBuffer[BUFFER_SIZE]; + sciPrintf("FIFO Burst Read:\r\n"); + size_t bytesRead = 0; + obc_error_code_t ret; + do { + ret = readImage(imgBuffer, BUFFER_SIZE, &bytesRead); + for (size_t index = 0; index < bytesRead; index++) { + sciPrintf("0x%X,", imgBuffer[index]); + } + } while (ret == OBC_ERR_CODE_CAMERA_IMAGE_READ_INCOMPLETE); + // Put Camera on standby (gets pretty hot if left powered on for too long) + standbyCamera(); while (1) ; } @@ -113,7 +90,7 @@ int main(void) { initSpiMutex(); initI2CMutex(); - xTaskCreateStatic(vTask1, "Arducam", 1024, NULL, 1, taskStack, &taskBuffer); + xTaskCreateStatic(vTask1, "Arducam", TASK_STACK_SIZE, NULL, 1, taskStack, &taskBuffer); vTaskStartScheduler(); diff --git a/obc/modules/camera_mgr/camera_control.c b/obc/modules/camera_mgr/camera_control.c index e4bd66663..c26453abe 100644 --- a/obc/modules/camera_mgr/camera_control.c +++ b/obc/modules/camera_mgr/camera_control.c @@ -3,20 +3,16 @@ static uint32_t totalBytesToRead[CAMERA_COUNT] = {0}; static uint32_t FIFOReadPtr[CAMERA_COUNT] = {0}; -size_t bytesLeftInFIFO(void) { - camera_id_t selectedCamera = getSelectedCamera(); - return (totalBytesToRead[selectedCamera] < FIFOReadPtr[selectedCamera]) - ? 0 - : totalBytesToRead[selectedCamera] - FIFOReadPtr[selectedCamera]; -} - obc_error_code_t initCamera(void) { obc_error_code_t errCode; memset(totalBytesToRead, 0, sizeof(size_t) * CAMERA_COUNT); memset(FIFOReadPtr, 0, sizeof(size_t) * CAMERA_COUNT); RETURN_IF_ERROR_CODE(resetCPLD()); + // Make sure sensor is powered and reset is not asserted (reset is active low). + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(SENSOR_POWER_EN_MASK | SENSOR_RESET_MASK)); + // Make sure sensor vsync timing is set to active low RETURN_IF_ERROR_CODE(arducamWriteSensorTimingControlReg(VSYNC_ACTIVE_LOW_MASK)); - return OBC_ERR_CODE_SUCCESS; + return errCode; } bool isCaptureDone(void) { @@ -26,6 +22,100 @@ bool isCaptureDone(void) { return (errCode == OBC_ERR_CODE_SUCCESS) ? (bool)(status & STATUS_CAPTURE_DONE_MASK) : true; } +obc_error_code_t startImageCapture(void) { + obc_error_code_t errCode; + camera_id_t selectedCamera = getSelectedCamera(); + RETURN_IF_ERROR_CODE(arducamWriteFIFOControlReg(FIFO_CLEAR_CAPTURE_DONE_FLAG | FIFO_START_CAPTURE)); + totalBytesToRead[selectedCamera] = 0; + FIFOReadPtr[selectedCamera] = 0; + return errCode; +} + +obc_error_code_t readImage(uint8_t* buffer, size_t bufferLen, size_t* bytesRead) { + if (buffer == NULL || bytesRead == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + obc_error_code_t errCode; + camera_id_t selectedCamera = getSelectedCamera(); + // Start of a new image, get image length + if (totalBytesToRead[selectedCamera] == 0) { + RETURN_IF_ERROR_CODE(arducamReadFIFOSize(&totalBytesToRead[selectedCamera])); + } + size_t bytesToRead = bytesLeftInFIFO(); + if (bytesToRead > bufferLen) { + bytesToRead = bufferLen; + } + + *bytesRead = 0; + RETURN_IF_ERROR_CODE(arducamBurstReadFIFO(buffer, bytesToRead)); + *bytesRead = bytesToRead; + FIFOReadPtr[selectedCamera] += bytesToRead; + if (bytesLeftInFIFO() > 0) { + errCode = OBC_ERR_CODE_CAMERA_IMAGE_READ_INCOMPLETE; + } + return errCode; +} + +size_t bytesLeftInFIFO(void) { + camera_id_t selectedCamera = getSelectedCamera(); + return (totalBytesToRead[selectedCamera] < FIFOReadPtr[selectedCamera]) + ? 0 + : totalBytesToRead[selectedCamera] - FIFOReadPtr[selectedCamera]; +} + +obc_error_code_t wakeupCamera(void) { + obc_error_code_t errCode; + uint8_t registerVal = 0; + RETURN_IF_ERROR_CODE(arducamReadSensorPowerControlReg(®isterVal)); + // Unset standby bit (active high) + registerVal &= (~SENSOR_STANDBY_MASK); + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(registerVal)); + return errCode; +} + +obc_error_code_t standbyCamera(void) { + obc_error_code_t errCode; + uint8_t registerVal = 0; + RETURN_IF_ERROR_CODE(arducamReadSensorPowerControlReg(®isterVal)); + // Set standby bit (active high) + registerVal |= (SENSOR_STANDBY_MASK); + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(registerVal)); + return errCode; +} + +obc_error_code_t powerOnCamera(void) { + obc_error_code_t errCode; + uint8_t registerVal = 0; + RETURN_IF_ERROR_CODE(arducamReadSensorPowerControlReg(®isterVal)); + // Set power en bit (active high) + registerVal |= (SENSOR_POWER_EN_MASK); + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(registerVal)); + return errCode; +} + +obc_error_code_t powerOffCamera(void) { + obc_error_code_t errCode; + uint8_t registerVal = 0; + RETURN_IF_ERROR_CODE(arducamReadSensorPowerControlReg(®isterVal)); + // Unset power en bit (active high) + registerVal &= (~SENSOR_POWER_EN_MASK); + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(registerVal)); + return errCode; +} + +obc_error_code_t resetCamera(void) { + obc_error_code_t errCode; + uint8_t registerVal = 0; + RETURN_IF_ERROR_CODE(arducamReadSensorPowerControlReg(®isterVal)); + // Unset reset bit (active low) + registerVal &= (~SENSOR_RESET_MASK); + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(registerVal)); + // Set reset bit + registerVal |= SENSOR_RESET_MASK; + RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(registerVal)); + return errCode; +} + obc_error_code_t camConfigureSensor(void) { obc_error_code_t errCode; // Reset camera diff --git a/obc/modules/camera_mgr/camera_control.h b/obc/modules/camera_mgr/camera_control.h index 482f3d503..aa9a1ee04 100644 --- a/obc/modules/camera_mgr/camera_control.h +++ b/obc/modules/camera_mgr/camera_control.h @@ -1,5 +1,38 @@ +#pragma once #include "arducam.h" +/** + * @brief Initialize selected camera. + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t initCamera(void); + +/** + * @brief Returns status of capture. + * @note Will return true if errors occur. Capture is done, just incorrectly. + * + * @return true if capture is done. + */ +bool isCaptureDone(void); + +/** + * @brief Starts image capture on selected camera. + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t startImageCapture(void); + +/** + * @brief Reads bufferLen number of bytes from camera FIFO. + * + * @param buffer Pointer to buffer. + * @param bufferLen Length of buffer in bytes. + * @param bytesRead Number of bytes read. + * @return obc_error_code_t + */ +obc_error_code_t readImage(uint8_t* buffer, size_t bufferLen, size_t* bytesRead); + /** * @brief Returns number of Bytes left in FIFO to read * @@ -8,16 +41,43 @@ size_t bytesLeftInFIFO(void); /** - * @brief Initialize selected camera. + * @brief Power up camera sensor our of Standby. + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -obc_error_code_t initCamera(void); +obc_error_code_t wakeupCamera(void); /** - * @brief Returns status of capture. - * @note Will return true if errors occur. Capture is done, just incorrectly. + * @brief Power down camera sensor into standby. Sensor configuration will NOT be lost. * - * @return true if capture is done. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -bool isCaptureDone(void); +obc_error_code_t standbyCamera(void); + +/** + * @brief Power on camera sensor. Sensor will have to be reconfigured. + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t powerOnCamera(void); +/** + * @brief Power off camera sensor. Sensor configuration will be lost. + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t powerOffCamera(void); + +/** + * @brief Reset camera sensor configuration. + * + * @return obc_error_code_t + */ +obc_error_code_t resetCamera(void); + +/** + * @brief Configures ov5642 sensor + * + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ obc_error_code_t camConfigureSensor(void); diff --git a/obc/sys/obc_errors.h b/obc/sys/obc_errors.h index 55fb69ec2..1de759df6 100644 --- a/obc/sys/obc_errors.h +++ b/obc/sys/obc_errors.h @@ -40,7 +40,7 @@ typedef enum { OBC_ERR_CODE_SPI_DESYNC_ERROR = 112, OBC_ERR_CODE_SPI_BIT_ERROR = 113, OBC_ERR_CODE_SPI_RX_OVERRUN = 114, - + OBC_ERR_CODE_CAMERA_IMAGE_READ_INCOMPLETE = 115, /* CDH errors 200 - 299 */ OBC_ERR_CODE_UNSUPPORTED_CMD = 200, OBC_ERR_CODE_CMD_NOT_ALLOWED = 201, From d4e0eedf527a560d2f8aa4b2fde20e8ce0453d36 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Mon, 1 Apr 2024 19:51:23 -0400 Subject: [PATCH 05/18] Updated some comments --- obc/modules/camera_mgr/camera_control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obc/modules/camera_mgr/camera_control.c b/obc/modules/camera_mgr/camera_control.c index c26453abe..859df5064 100644 --- a/obc/modules/camera_mgr/camera_control.c +++ b/obc/modules/camera_mgr/camera_control.c @@ -120,7 +120,7 @@ obc_error_code_t camConfigureSensor(void) { obc_error_code_t errCode; // Reset camera RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(0x3008, 0x80)); - // Setup at 320x420 resolution + // Setup Preview resolution RETURN_IF_ERROR_CODE(camWriteSensorRegs16_8(getCamPreviewConfig(), PREVIEW_CONFIG_LEN)); vTaskDelay(pdMS_TO_TICKS(1)); From 32af8c4e4199fb18cadde882e40c73244aaf4974 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Mon, 1 Apr 2024 21:35:37 -0400 Subject: [PATCH 06/18] Fix unit test build error --- test/test_obc/unit/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_obc/unit/CMakeLists.txt b/test/test_obc/unit/CMakeLists.txt index ffd604cce..e6741ab2f 100644 --- a/test/test_obc/unit/CMakeLists.txt +++ b/test/test_obc/unit/CMakeLists.txt @@ -2,7 +2,7 @@ set(TEST_BINARY obc-firmware-tests) set(TEST_DEPENDENCIES ${CMAKE_SOURCE_DIR}/obc/app/sys/time/obc_time_utils.c - ${CMAKE_SOURCE_DIR}/obc/app/drivers/arducam/image_processing.c + ${CMAKE_SOURCE_DIR}/obc/app/modules/camera_mgr/image_processing.c ${CMAKE_SOURCE_DIR}/obc/app/drivers/vn100/vn100_binary_parsing.c ${CMAKE_SOURCE_DIR}/interfaces/obc_gs_interface/common/obc_gs_crc.c ${CMAKE_SOURCE_DIR}/interfaces/data_pack_unpack/data_unpack_utils.c @@ -35,7 +35,7 @@ target_include_directories(${TEST_BINARY} ${CMAKE_SOURCE_DIR}/obc/app/sys/logging ${CMAKE_SOURCE_DIR}/obc/app/sys/persistent ${CMAKE_SOURCE_DIR}/obc/app/drivers/ds3232 - ${CMAKE_SOURCE_DIR}/obc/app/drivers/arducam + ${CMAKE_SOURCE_DIR}/obc/app/modules/camera_mgr ${CMAKE_SOURCE_DIR}/obc/app/drivers/vn100 ${CMAKE_SOURCE_DIR}/interfaces/obc_gs_interface/common ${CMAKE_SOURCE_DIR}/interfaces/data_pack_unpack From 49ccda384837ec17756094896043b5975c5ecc94 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Sat, 22 Jun 2024 15:23:02 -0400 Subject: [PATCH 07/18] Moved Camera Img read incomplete error to payload errors --- obc/app/sys/obc_errors.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/obc/app/sys/obc_errors.h b/obc/app/sys/obc_errors.h index 1de759df6..2d7eba754 100644 --- a/obc/app/sys/obc_errors.h +++ b/obc/app/sys/obc_errors.h @@ -40,7 +40,7 @@ typedef enum { OBC_ERR_CODE_SPI_DESYNC_ERROR = 112, OBC_ERR_CODE_SPI_BIT_ERROR = 113, OBC_ERR_CODE_SPI_RX_OVERRUN = 114, - OBC_ERR_CODE_CAMERA_IMAGE_READ_INCOMPLETE = 115, + /* CDH errors 200 - 299 */ OBC_ERR_CODE_UNSUPPORTED_CMD = 200, OBC_ERR_CODE_CMD_NOT_ALLOWED = 201, @@ -83,6 +83,7 @@ typedef enum { /* Payload errors 600 - 699 */ OBC_ERR_CODE_FRAME_SIZE_OUT_OF_RANGE = 600, + OBC_ERR_CODE_CAMERA_IMAGE_READ_INCOMPLETE = 601, /* File System errors 700 - 799 */ OBC_ERR_CODE_INVALID_FILE_NAME = 700, From 7a886d6fb41dad0a68f3ab2595d3463c07d31f3f Mon Sep 17 00:00:00 2001 From: George Jiang Date: Sat, 22 Jun 2024 15:34:27 -0400 Subject: [PATCH 08/18] Update getCaptureStatus to return errCode; Updated initCamera to only initSelected camera --- obc/app/modules/camera_mgr/camera_control.c | 10 ++++++---- obc/app/modules/camera_mgr/camera_control.h | 7 ++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/obc/app/modules/camera_mgr/camera_control.c b/obc/app/modules/camera_mgr/camera_control.c index 859df5064..10696e26b 100644 --- a/obc/app/modules/camera_mgr/camera_control.c +++ b/obc/app/modules/camera_mgr/camera_control.c @@ -5,8 +5,9 @@ static uint32_t FIFOReadPtr[CAMERA_COUNT] = {0}; obc_error_code_t initCamera(void) { obc_error_code_t errCode; - memset(totalBytesToRead, 0, sizeof(size_t) * CAMERA_COUNT); - memset(FIFOReadPtr, 0, sizeof(size_t) * CAMERA_COUNT); + camera_id_t selectedCamera = getSelectedCamera(); + totalBytesToRead[selectedCamera] = 0; + FIFOReadPtr[selectedCamera] = 0; RETURN_IF_ERROR_CODE(resetCPLD()); // Make sure sensor is powered and reset is not asserted (reset is active low). RETURN_IF_ERROR_CODE(arducamWriteSensorPowerControlReg(SENSOR_POWER_EN_MASK | SENSOR_RESET_MASK)); @@ -15,11 +16,12 @@ obc_error_code_t initCamera(void) { return errCode; } -bool isCaptureDone(void) { +obc_error_code_t isCaptureDone(bool* caputreStatus) { obc_error_code_t errCode; uint8_t status; LOG_IF_ERROR_CODE(arducamReadCaptureStatusReg(&status)); - return (errCode == OBC_ERR_CODE_SUCCESS) ? (bool)(status & STATUS_CAPTURE_DONE_MASK) : true; + *caputreStatus = (errCode == OBC_ERR_CODE_SUCCESS) ? (bool)(status & STATUS_CAPTURE_DONE_MASK) : false; + return errCode; } obc_error_code_t startImageCapture(void) { diff --git a/obc/app/modules/camera_mgr/camera_control.h b/obc/app/modules/camera_mgr/camera_control.h index aa9a1ee04..10ad3ed97 100644 --- a/obc/app/modules/camera_mgr/camera_control.h +++ b/obc/app/modules/camera_mgr/camera_control.h @@ -10,11 +10,12 @@ obc_error_code_t initCamera(void); /** * @brief Returns status of capture. - * @note Will return true if errors occur. Capture is done, just incorrectly. + * @param captureStatus pointer to bool that will store capture status. + * @note Will return false if errors occur. Make sure to check for error codes. * - * @return true if capture is done. + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. */ -bool isCaptureDone(void); +obc_error_code_t isCaptureDone(bool* captureStatus); /** * @brief Starts image capture on selected camera. From b9ebcdf76403eaa2aed0324a1b94ac27668346dc Mon Sep 17 00:00:00 2001 From: George Jiang Date: Sat, 22 Jun 2024 15:42:21 -0400 Subject: [PATCH 09/18] Update getCaptureStatus to return new camera capture error codes --- obc/app/modules/camera_mgr/camera_control.c | 8 ++++---- obc/app/modules/camera_mgr/camera_control.h | 7 +++---- obc/app/sys/obc_errors.h | 2 ++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/obc/app/modules/camera_mgr/camera_control.c b/obc/app/modules/camera_mgr/camera_control.c index 10696e26b..195780e9d 100644 --- a/obc/app/modules/camera_mgr/camera_control.c +++ b/obc/app/modules/camera_mgr/camera_control.c @@ -16,12 +16,12 @@ obc_error_code_t initCamera(void) { return errCode; } -obc_error_code_t isCaptureDone(bool* caputreStatus) { +obc_error_code_t isCaptureDone(void) { obc_error_code_t errCode; uint8_t status; - LOG_IF_ERROR_CODE(arducamReadCaptureStatusReg(&status)); - *caputreStatus = (errCode == OBC_ERR_CODE_SUCCESS) ? (bool)(status & STATUS_CAPTURE_DONE_MASK) : false; - return errCode; + RETURN_IF_ERROR_CODE(arducamReadCaptureStatusReg(&status)); + return ((bool)(status & STATUS_CAPTURE_DONE_MASK)) ? OBC_ERR_CODE_CAMERA_CAPTURE_COMPLETE + : OBC_ERR_CODE_CAMERA_CAPTURE_INCOMPLETE; } obc_error_code_t startImageCapture(void) { diff --git a/obc/app/modules/camera_mgr/camera_control.h b/obc/app/modules/camera_mgr/camera_control.h index 10ad3ed97..4611c57aa 100644 --- a/obc/app/modules/camera_mgr/camera_control.h +++ b/obc/app/modules/camera_mgr/camera_control.h @@ -10,12 +10,11 @@ obc_error_code_t initCamera(void); /** * @brief Returns status of capture. - * @param captureStatus pointer to bool that will store capture status. - * @note Will return false if errors occur. Make sure to check for error codes. * - * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + * @return Error code. OBC_ERR_CODE_CAMERA_CAPTURE_COMPLETE if capture is complete, + * OBC_ERR_CODE_CAMERA_CAPTURE_INCOMPLETE if capture is INCOMPLETE. Any error codes otherwise. */ -obc_error_code_t isCaptureDone(bool* captureStatus); +obc_error_code_t isCaptureDone(void); /** * @brief Starts image capture on selected camera. diff --git a/obc/app/sys/obc_errors.h b/obc/app/sys/obc_errors.h index 2d7eba754..03b5d6c43 100644 --- a/obc/app/sys/obc_errors.h +++ b/obc/app/sys/obc_errors.h @@ -84,6 +84,8 @@ typedef enum { /* Payload errors 600 - 699 */ OBC_ERR_CODE_FRAME_SIZE_OUT_OF_RANGE = 600, OBC_ERR_CODE_CAMERA_IMAGE_READ_INCOMPLETE = 601, + OBC_ERR_CODE_CAMERA_CAPTURE_COMPLETE = 602, + OBC_ERR_CODE_CAMERA_CAPTURE_INCOMPLETE = 603, /* File System errors 700 - 799 */ OBC_ERR_CODE_INVALID_FILE_NAME = 700, From 74fd73f2bb08d500eb01eaa85f1976a1c29948a1 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Fri, 2 Aug 2024 18:11:34 -0400 Subject: [PATCH 10/18] Updated arducam example app --- obc/examples/test_app_arducam/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/obc/examples/test_app_arducam/main.c b/obc/examples/test_app_arducam/main.c index 6f47d568f..bf7789410 100644 --- a/obc/examples/test_app_arducam/main.c +++ b/obc/examples/test_app_arducam/main.c @@ -52,7 +52,7 @@ void vTask1(void *pvParameters) { // Capture sciPrintf("Starting Image Capture\r\n"); startImageCapture(); - while (!isCaptureDone()) + while (isCaptureDone() == OBC_ERR_CODE_CAMERA_CAPTURE_INCOMPLETE) ; sciPrintf("Image Capture Done ^_^\r\n"); From f3b276caad74e97385d7590dcb6a345a0cd3eb00 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Fri, 2 Aug 2024 18:45:48 -0400 Subject: [PATCH 11/18] Added non-driver function to select camera --- obc/app/drivers/arducam/arducam.c | 2 +- obc/app/drivers/arducam/arducam.h | 2 +- obc/app/modules/camera_mgr/camera_control.c | 9 +++++++++ obc/app/modules/camera_mgr/camera_control.h | 8 ++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/obc/app/drivers/arducam/arducam.c b/obc/app/drivers/arducam/arducam.c index 634f4c6a2..190770686 100644 --- a/obc/app/drivers/arducam/arducam.c +++ b/obc/app/drivers/arducam/arducam.c @@ -77,7 +77,7 @@ typedef enum opcode { ARDUCAM_RESET_CPLD, } opcode_t; -void selectCamera(camera_id_t cameraID) { selectedCamera = cameraID; } +void selectCameraSPIBus(camera_id_t cameraID) { selectedCamera = cameraID; } camera_id_t getSelectedCamera(void) { return selectedCamera; } diff --git a/obc/app/drivers/arducam/arducam.h b/obc/app/drivers/arducam/arducam.h index ada05ad00..20f6ba37d 100644 --- a/obc/app/drivers/arducam/arducam.h +++ b/obc/app/drivers/arducam/arducam.h @@ -47,7 +47,7 @@ typedef enum { * * @param cameraID Camera ID of the camera to be selected. */ -void selectCamera(camera_id_t cameraID); +void selectCameraSPIBus(camera_id_t cameraID); /** * @brief Returns the camera id of the selected camera. diff --git a/obc/app/modules/camera_mgr/camera_control.c b/obc/app/modules/camera_mgr/camera_control.c index 195780e9d..6e9ef0f64 100644 --- a/obc/app/modules/camera_mgr/camera_control.c +++ b/obc/app/modules/camera_mgr/camera_control.c @@ -3,6 +3,15 @@ static uint32_t totalBytesToRead[CAMERA_COUNT] = {0}; static uint32_t FIFOReadPtr[CAMERA_COUNT] = {0}; +obc_error_code_t selectCamera(camera_id_t cameraID) { + // Set SPI bus of selected camera + selectCameraSPIBus(cameraID); + + // TODO: Add I2C mux select for camera + + return OBC_ERR_CODE_SUCCESS; +} + obc_error_code_t initCamera(void) { obc_error_code_t errCode; camera_id_t selectedCamera = getSelectedCamera(); diff --git a/obc/app/modules/camera_mgr/camera_control.h b/obc/app/modules/camera_mgr/camera_control.h index 4611c57aa..982591491 100644 --- a/obc/app/modules/camera_mgr/camera_control.h +++ b/obc/app/modules/camera_mgr/camera_control.h @@ -1,6 +1,14 @@ #pragma once #include "arducam.h" +/** + * @brief Sets the SPI bus and I2C mux for a specific camera + * + * @param camID Camera ID + * @return Error code. OBC_ERR_CODE_SUCCESS if successful. + */ +obc_error_code_t selectCamera(camera_id_t camID); + /** * @brief Initialize selected camera. * From 1321b2a17484f42b461f7f4eb0deef21d7f2291b Mon Sep 17 00:00:00 2001 From: George Jiang Date: Fri, 2 Aug 2024 18:50:37 -0400 Subject: [PATCH 12/18] Expanded on TODOs for I2C mux --- obc/app/drivers/tca9458a/tca9458a.c | 3 +++ obc/app/modules/camera_mgr/camera_control.c | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/obc/app/drivers/tca9458a/tca9458a.c b/obc/app/drivers/tca9458a/tca9458a.c index ad112c26d..1712df563 100644 --- a/obc/app/drivers/tca9458a/tca9458a.c +++ b/obc/app/drivers/tca9458a/tca9458a.c @@ -12,6 +12,9 @@ #define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) // TODO: Fully develop and test this driver +// 1. Check if more features need to be implemented +// 2. Test driver +// 3. Integrate with camera control obc_error_code_t tcaSelect(uint8_t portNum) { uint8_t tca = 0; diff --git a/obc/app/modules/camera_mgr/camera_control.c b/obc/app/modules/camera_mgr/camera_control.c index 6e9ef0f64..17d436b3b 100644 --- a/obc/app/modules/camera_mgr/camera_control.c +++ b/obc/app/modules/camera_mgr/camera_control.c @@ -1,4 +1,5 @@ #include "camera_control.h" +#include "tca9458a.h" static uint32_t totalBytesToRead[CAMERA_COUNT] = {0}; static uint32_t FIFOReadPtr[CAMERA_COUNT] = {0}; @@ -7,8 +8,8 @@ obc_error_code_t selectCamera(camera_id_t cameraID) { // Set SPI bus of selected camera selectCameraSPIBus(cameraID); - // TODO: Add I2C mux select for camera - + // TODO: Validate I2C mux driver code and properly integrate with control code + // RETURN_IF_ERROR_CODE(tcaSelect((uint8_t) cameraID)); return OBC_ERR_CODE_SUCCESS; } From 9b228ceecc978f27544becd034ee7b3dd8e2c5ec Mon Sep 17 00:00:00 2001 From: George Jiang Date: Fri, 2 Aug 2024 18:54:35 -0400 Subject: [PATCH 13/18] Fix build errors --- obc/app/drivers/CMakeLists.txt | 2 ++ obc/app/drivers/tca9458a/tca9458a.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/obc/app/drivers/CMakeLists.txt b/obc/app/drivers/CMakeLists.txt index f8ae8cff7..fa42ab214 100644 --- a/obc/app/drivers/CMakeLists.txt +++ b/obc/app/drivers/CMakeLists.txt @@ -4,6 +4,7 @@ SET(INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/rm46 ${CMAKE_CURRENT_SOURCE_DIR}/arducam + ${CMAKE_CURRENT_SOURCE_DIR}/tca9458a ${CMAKE_CURRENT_SOURCE_DIR}/cc1120 ${CMAKE_CURRENT_SOURCE_DIR}/ds3232 ${CMAKE_CURRENT_SOURCE_DIR}/fram @@ -30,6 +31,7 @@ SET(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/arducam/arducam.c ${CMAKE_CURRENT_SOURCE_DIR}/arducam/ov5642_config.c + ${CMAKE_CURRENT_SOURCE_DIR}/tca9458a/tca9458a.c ${CMAKE_CURRENT_SOURCE_DIR}/cc1120/cc1120_mcu.c ${CMAKE_CURRENT_SOURCE_DIR}/cc1120/cc1120.c diff --git a/obc/app/drivers/tca9458a/tca9458a.h b/obc/app/drivers/tca9458a/tca9458a.h index fbad0bddf..74fc2778b 100644 --- a/obc/app/drivers/tca9458a/tca9458a.h +++ b/obc/app/drivers/tca9458a/tca9458a.h @@ -2,7 +2,6 @@ #include "stdint.h" #include "obc_spi_io.h" -#include "ov5642_reg.h" #include "obc_board_config.h" /** From ec5f8a92467646c2dcc508616ec07fec3ef91f65 Mon Sep 17 00:00:00 2001 From: George Jiang Date: Fri, 2 Aug 2024 18:59:28 -0400 Subject: [PATCH 14/18] More todo comments --- obc/app/modules/camera_mgr/camera_control.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/obc/app/modules/camera_mgr/camera_control.c b/obc/app/modules/camera_mgr/camera_control.c index 17d436b3b..3c19f4060 100644 --- a/obc/app/modules/camera_mgr/camera_control.c +++ b/obc/app/modules/camera_mgr/camera_control.c @@ -128,6 +128,9 @@ obc_error_code_t resetCamera(void) { return errCode; } +// TODO: Find proper config settings and capture sequence +// Following config step is ripped straight from arduino arducam example files, unsure how +// Camera is generating images, just super under exposed, brightness super low obc_error_code_t camConfigureSensor(void) { obc_error_code_t errCode; // Reset camera From e49a51c512bc480e5e3810deaa26e20274c127cf Mon Sep 17 00:00:00 2001 From: tangerine238 Date: Wed, 30 Oct 2024 11:00:31 -0400 Subject: [PATCH 15/18] fixed most comments --- obc/app/drivers/arducam/arducam.c | 78 +++++++++++++++---------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/obc/app/drivers/arducam/arducam.c b/obc/app/drivers/arducam/arducam.c index 190770686..1a0d1112a 100644 --- a/obc/app/drivers/arducam/arducam.c +++ b/obc/app/drivers/arducam/arducam.c @@ -57,24 +57,24 @@ static const uint8_t cameraCS[CAMERA_COUNT] = { static camera_id_t selectedCamera = PRIMARY; typedef enum opcode { - ARDUCAM_READ_TEST_REG, - ARDUCAM_WRITE_TEST_REG, - ARDUCAM_READ_CAPTURE_CONTROL_REG, - ARDUCAM_WRITE_CAPTURE_CONTROL_REG, - ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG, - ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG, - ARDUCAM_READ_FIFO_CONTROL_REG, - ARDUCAM_WRITE_FIFO_CONTROL_REG, - ARDUCAM_READ_SENSOR_POWER_CONTROL_REG, - ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG, - ARDUCAM_FIFO_BURST_READ, - ARDUCAM_FIFO_READ, - ARDUCAM_READ_FW_VERSION, - ARDUCAM_READ_CAPTURE_STATUS_REG, - ARDUCAM_READ_FIFO_SIZE_LOWER, - ARDUCAM_READ_FIFO_SIZE_MIDDLE, - ARDUCAM_READ_FIFO_SIZE_UPPER, - ARDUCAM_RESET_CPLD, + ARDUCAM_READ_TEST_REG = 0x01, + ARDUCAM_WRITE_TEST_REG = 0x02, + ARDUCAM_READ_CAPTURE_CONTROL_REG = 0x03, + ARDUCAM_WRITE_CAPTURE_CONTROL_REG = 0x04, + ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG = 0x05, + ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG = 0x06, + ARDUCAM_READ_FIFO_CONTROL_REG = 0x07, + ARDUCAM_WRITE_FIFO_CONTROL_REG = 0x08, + ARDUCAM_READ_SENSOR_POWER_CONTROL_REG = 0x09, + ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG = 0x10, + ARDUCAM_FIFO_BURST_READ = 0x11, + ARDUCAM_FIFO_READ = 0x12, + ARDUCAM_READ_FW_VERSION = 0x13, + ARDUCAM_READ_CAPTURE_STATUS_REG = 0x14, + ARDUCAM_READ_FIFO_SIZE_LOWER = 0x15, + ARDUCAM_READ_FIFO_SIZE_MIDDLE = 0x16, + ARDUCAM_READ_FIFO_SIZE_UPPER = 0x17, + ARDUCAM_RESET_CPLD = 0x18, } opcode_t; void selectCameraSPIBus(camera_id_t cameraID) { selectedCamera = cameraID; } @@ -86,64 +86,62 @@ static obc_error_code_t arducamTransmitOpcode(opcode_t opcode) { obc_error_code_t errCode; switch (opcode) { case ARDUCAM_READ_TEST_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_TEST_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_TEST_REG)); break; case ARDUCAM_WRITE_TEST_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_TEST_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_TEST_REG)); break; case ARDUCAM_READ_CAPTURE_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_CAPTURE_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_CAPTURE_CONTROL_REG)); break; case ARDUCAM_WRITE_CAPTURE_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_CAPTURE_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_CAPTURE_CONTROL_REG)); break; case ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_SENSOR_TIMING_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG)); break; case ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_SENSOR_TIMING_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG)); break; case ARDUCAM_READ_FIFO_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_CONTROL_REG)); break; case ARDUCAM_WRITE_FIFO_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_FIFO_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_FIFO_CONTROL_REG)); break; case ARDUCAM_READ_SENSOR_POWER_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_SENSOR_POWER_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_SENSOR_POWER_CONTROL_REG)); break; case ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_WRITE_SENSOR_POWER_CONTROL_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG)); break; case ARDUCAM_FIFO_BURST_READ: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_FIFO_BURST_READ)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_FIFO_BURST_READ)); break; case ARDUCAM_FIFO_READ: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_FIFO_READ)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_FIFO_READ)); break; case ARDUCAM_READ_FW_VERSION: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FW_VERSION)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FW_VERSION)); break; case ARDUCAM_READ_CAPTURE_STATUS_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_CAPTURE_STATUS_REG)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_CAPTURE_STATUS_REG)); break; case ARDUCAM_READ_FIFO_SIZE_LOWER: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_SIZE_LOWER)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_SIZE_LOWER)); break; case ARDUCAM_READ_FIFO_SIZE_MIDDLE: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_SIZE_MIDDLE)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_SIZE_MIDDLE)); break; case ARDUCAM_READ_FIFO_SIZE_UPPER: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_READ_FIFO_SIZE_UPPER)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_SIZE_UPPER)); break; case ARDUCAM_RESET_CPLD: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, OP_RESET_CPLD)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_RESET_CPLD)); break; default: LOG_ERROR_CODE(OBC_ERR_CODE_INVALID_ARG); - errCode = OBC_ERR_CODE_INVALID_ARG; } - return errCode; } @@ -488,7 +486,7 @@ obc_error_code_t resetCPLD(void) { LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_RESET_CPLD)); if (errCode == OBC_ERR_CODE_SUCCESS) { LOG_IF_ERROR_CODE( - spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, (ARDUCAM_RESET_CPLD_MASK & (~ARDUCAM_RESET_CPLD_MASK)))); + spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, 0)); } // Reset overwritten error code prevCode = errCode; @@ -511,7 +509,7 @@ obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t *regDat) { return errCode; } -obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], uint16_t reglistLen) { +obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], size_t reglistLen) { obc_error_code_t errCode; for (int i = 0; i < reglistLen; i++) { From 868c1eb59adb3836f5709c1ca713c20844172db1 Mon Sep 17 00:00:00 2001 From: tangerine238 Date: Thu, 31 Oct 2024 10:06:21 -0400 Subject: [PATCH 16/18] made more changes --- obc/app/drivers/arducam/arducam.c | 116 +++++------------------------- 1 file changed, 19 insertions(+), 97 deletions(-) diff --git a/obc/app/drivers/arducam/arducam.c b/obc/app/drivers/arducam/arducam.c index 1a0d1112a..e2709b2a7 100644 --- a/obc/app/drivers/arducam/arducam.c +++ b/obc/app/drivers/arducam/arducam.c @@ -18,28 +18,8 @@ #define ARDUCAM_DELAY_2MS pdMS_TO_TICKS(2) // Arduchip masks -#define ARDUCHIP_WRITE_MASK 0x80 #define ARDUCAM_RESET_CPLD_MASK 0x80 -// Arduchip Opcodes -#define OP_READ_TEST_REG 0x00 -#define OP_READ_CAPTURE_CONTROL_REG 0x01 -#define OP_READ_SENSOR_TIMING_CONTROL_REG 0x03 -#define OP_READ_FIFO_CONTROL_REG 0x04 -#define OP_READ_SENSOR_POWER_CONTROL_REG 0x06 -#define OP_RESET_CPLD (0x07 | ARDUCHIP_WRITE_MASK) -#define OP_FIFO_BURST_READ 0x3C -#define OP_FIFO_READ 0x3D -#define OP_READ_FW_VERSION 0x40 -#define OP_READ_CAPTURE_STATUS_REG 0x41 -#define OP_READ_FIFO_SIZE_LOWER 0x42 -#define OP_READ_FIFO_SIZE_MIDDLE 0x43 -#define OP_READ_FIFO_SIZE_UPPER 0x44 -#define OP_WRITE_TEST_REG (OP_READ_TEST_REG | ARDUCHIP_WRITE_MASK) -#define OP_WRITE_CAPTURE_CONTROL_REG (OP_READ_CAPTURE_CONTROL_REG | ARDUCHIP_WRITE_MASK) -#define OP_WRITE_SENSOR_TIMING_CONTROL_REG (OP_READ_SENSOR_TIMING_CONTROL_REG | ARDUCHIP_WRITE_MASK) -#define OP_WRITE_FIFO_CONTROL_REG (OP_READ_FIFO_CONTROL_REG | ARDUCHIP_WRITE_MASK) -#define OP_WRITE_SENSOR_POWER_CONTROL_REG (OP_READ_SENSOR_POWER_CONTROL_REG | ARDUCHIP_WRITE_MASK) // Camera Img Sensor (I2C) defines #define CAM_I2C_ADDR 0x3C @@ -57,24 +37,24 @@ static const uint8_t cameraCS[CAMERA_COUNT] = { static camera_id_t selectedCamera = PRIMARY; typedef enum opcode { - ARDUCAM_READ_TEST_REG = 0x01, - ARDUCAM_WRITE_TEST_REG = 0x02, - ARDUCAM_READ_CAPTURE_CONTROL_REG = 0x03, - ARDUCAM_WRITE_CAPTURE_CONTROL_REG = 0x04, - ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG = 0x05, - ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG = 0x06, - ARDUCAM_READ_FIFO_CONTROL_REG = 0x07, - ARDUCAM_WRITE_FIFO_CONTROL_REG = 0x08, - ARDUCAM_READ_SENSOR_POWER_CONTROL_REG = 0x09, - ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG = 0x10, - ARDUCAM_FIFO_BURST_READ = 0x11, - ARDUCAM_FIFO_READ = 0x12, - ARDUCAM_READ_FW_VERSION = 0x13, - ARDUCAM_READ_CAPTURE_STATUS_REG = 0x14, - ARDUCAM_READ_FIFO_SIZE_LOWER = 0x15, - ARDUCAM_READ_FIFO_SIZE_MIDDLE = 0x16, - ARDUCAM_READ_FIFO_SIZE_UPPER = 0x17, - ARDUCAM_RESET_CPLD = 0x18, + ARDUCAM_READ_TEST_REG = 0x00, + ARDUCAM_WRITE_TEST_REG = (0x00 | 0x80), + ARDUCAM_READ_CAPTURE_CONTROL_REG = 0x01, + ARDUCAM_WRITE_CAPTURE_CONTROL_REG = (0x01 | 0x80), + ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG = 0x03, + ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG = (0x03 | 0x80), + ARDUCAM_READ_FIFO_CONTROL_REG = 0x04, + ARDUCAM_WRITE_FIFO_CONTROL_REG = (0x04 | 0x80), + ARDUCAM_READ_SENSOR_POWER_CONTROL_REG = 0x06, + ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG = (0x06| 0x80), + ARDUCAM_FIFO_BURST_READ = 0x3C, + ARDUCAM_FIFO_READ = 0x3D, + ARDUCAM_READ_FW_VERSION = 0x40, + ARDUCAM_READ_CAPTURE_STATUS_REG = 0x41, + ARDUCAM_READ_FIFO_SIZE_LOWER = 0x42, + ARDUCAM_READ_FIFO_SIZE_MIDDLE = 0x43, + ARDUCAM_READ_FIFO_SIZE_UPPER = 0x44, + ARDUCAM_RESET_CPLD = (0x07 | 0x80), } opcode_t; void selectCameraSPIBus(camera_id_t cameraID) { selectedCamera = cameraID; } @@ -84,65 +64,7 @@ camera_id_t getSelectedCamera(void) { return selectedCamera; } // CS assumed to be asserted static obc_error_code_t arducamTransmitOpcode(opcode_t opcode) { obc_error_code_t errCode; - switch (opcode) { - case ARDUCAM_READ_TEST_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_TEST_REG)); - break; - case ARDUCAM_WRITE_TEST_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_TEST_REG)); - break; - case ARDUCAM_READ_CAPTURE_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_CAPTURE_CONTROL_REG)); - break; - case ARDUCAM_WRITE_CAPTURE_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_CAPTURE_CONTROL_REG)); - break; - case ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_SENSOR_TIMING_CONTROL_REG)); - break; - case ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_SENSOR_TIMING_CONTROL_REG)); - break; - case ARDUCAM_READ_FIFO_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_CONTROL_REG)); - break; - case ARDUCAM_WRITE_FIFO_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_FIFO_CONTROL_REG)); - break; - case ARDUCAM_READ_SENSOR_POWER_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_SENSOR_POWER_CONTROL_REG)); - break; - case ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG)); - break; - case ARDUCAM_FIFO_BURST_READ: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_FIFO_BURST_READ)); - break; - case ARDUCAM_FIFO_READ: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_FIFO_READ)); - break; - case ARDUCAM_READ_FW_VERSION: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FW_VERSION)); - break; - case ARDUCAM_READ_CAPTURE_STATUS_REG: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_CAPTURE_STATUS_REG)); - break; - case ARDUCAM_READ_FIFO_SIZE_LOWER: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_SIZE_LOWER)); - break; - case ARDUCAM_READ_FIFO_SIZE_MIDDLE: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_SIZE_MIDDLE)); - break; - case ARDUCAM_READ_FIFO_SIZE_UPPER: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_READ_FIFO_SIZE_UPPER)); - break; - case ARDUCAM_RESET_CPLD: - LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, ARDUCAM_RESET_CPLD)); - break; - default: - LOG_ERROR_CODE(OBC_ERR_CODE_INVALID_ARG); - } - return errCode; + return LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, opcode)); } obc_error_code_t arducamReadTestReg(uint8_t *buffer) { From 2567f4fc2b46aa7d632fd15c3b203e238a0650d3 Mon Sep 17 00:00:00 2001 From: tangerine238 Date: Thu, 7 Nov 2024 10:09:36 -0500 Subject: [PATCH 17/18] fixing build task and comments --- .github/workflows/obc_examples.yml | 61 ++++++ obc/app/drivers/arducam/arducam.c | 14 +- obc/app/drivers/arducam/arducam.h | 2 +- obc/app/drivers/arducam/camera_reg.c | 99 +++++++++ obc/app/drivers/arducam/camera_reg.h | 96 +++++++++ obc/app/drivers/arducam/image_processing.c | 28 +++ obc/app/drivers/arducam/image_processing.h | 38 ++++ obc/app/drivers/arducam/ov5642_reg.c | 192 ++++++++++++++++++ obc/app/drivers/arducam/ov5642_reg.h | 31 +++ obc/app/modules/camera_mgr/CMakeLists.txt | 12 ++ .../test_app_cc1120_spi/cc1120_spi_tests.c | 95 +++++++++ .../test_app_cc1120_spi/cc1120_spi_tests.h | 18 ++ obc/examples/test_app_cc1120_spi/main.c | 53 +++++ obc/examples/test_app_rs/main.c | 63 ++++++ .../peripheral_config_definitions.cmake | 19 ++ 15 files changed, 812 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/obc_examples.yml create mode 100644 obc/app/drivers/arducam/camera_reg.c create mode 100644 obc/app/drivers/arducam/camera_reg.h create mode 100644 obc/app/drivers/arducam/image_processing.c create mode 100644 obc/app/drivers/arducam/image_processing.h create mode 100644 obc/app/drivers/arducam/ov5642_reg.c create mode 100644 obc/app/drivers/arducam/ov5642_reg.h create mode 100644 obc/app/modules/camera_mgr/CMakeLists.txt create mode 100644 obc/examples/test_app_cc1120_spi/cc1120_spi_tests.c create mode 100644 obc/examples/test_app_cc1120_spi/cc1120_spi_tests.h create mode 100644 obc/examples/test_app_cc1120_spi/main.c create mode 100644 obc/examples/test_app_rs/main.c create mode 100644 obc/shared/config/peripheral_config_definitions.cmake diff --git a/.github/workflows/obc_examples.yml b/.github/workflows/obc_examples.yml new file mode 100644 index 000000000..4ff81c8eb --- /dev/null +++ b/.github/workflows/obc_examples.yml @@ -0,0 +1,61 @@ +name: OBC Examples +on: + pull_request: + push: + branches: + - main + +jobs: + setup: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup + run: | + sudo apt-get update + sudo apt-get -y install build-essential cmake + + build: + runs-on: ubuntu-latest + needs: setup + + strategy: + matrix: + example: + [ + DMA_SPI, + FRAM_PERSIST, + FRAM_SPI, + LM75BD, + # MPU6050, + RE_SD, + # RTC, + UART_RX, + UART_TX, + VN100, + # CC1120_SPI, + RS, + ADC, + + # ADD NEW EXAMPLES ABOVE THIS LINE, MUST BE INLINE WITH OTHER EXAMPLES + ] + board: [ + RM46_LAUNCHPAD, + OBC_REVISION_1, + OBC_REVISION_2, + ] + + steps: + - uses: actions/checkout@v3 + + - name: Create binary directory + run: | + mkdir build + + - name: Build (Examples-${{ matrix.board }} ${{ matrix.example }}) + run: | + cd build + cmake .. -DCMAKE_BUILD_TYPE=Examples -DEXAMPLE_TYPE=${{matrix.example}} -DBOARD_TYPE=${{matrix.board}} -G"Unix Makefiles" -DDEBUG=1 + make diff --git a/obc/app/drivers/arducam/arducam.c b/obc/app/drivers/arducam/arducam.c index e2709b2a7..307f5d032 100644 --- a/obc/app/drivers/arducam/arducam.c +++ b/obc/app/drivers/arducam/arducam.c @@ -20,7 +20,6 @@ // Arduchip masks #define ARDUCAM_RESET_CPLD_MASK 0x80 - // Camera Img Sensor (I2C) defines #define CAM_I2C_ADDR 0x3C #define I2C_MUTEX_TIMEOUT portMAX_DELAY @@ -37,7 +36,7 @@ static const uint8_t cameraCS[CAMERA_COUNT] = { static camera_id_t selectedCamera = PRIMARY; typedef enum opcode { - ARDUCAM_READ_TEST_REG = 0x00, + ARDUCAM_READ_TEST_REG = 0x00, ARDUCAM_WRITE_TEST_REG = (0x00 | 0x80), ARDUCAM_READ_CAPTURE_CONTROL_REG = 0x01, ARDUCAM_WRITE_CAPTURE_CONTROL_REG = (0x01 | 0x80), @@ -46,7 +45,7 @@ typedef enum opcode { ARDUCAM_READ_FIFO_CONTROL_REG = 0x04, ARDUCAM_WRITE_FIFO_CONTROL_REG = (0x04 | 0x80), ARDUCAM_READ_SENSOR_POWER_CONTROL_REG = 0x06, - ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG = (0x06| 0x80), + ARDUCAM_WRITE_SENSOR_POWER_CONTROL_REG = (0x06 | 0x80), ARDUCAM_FIFO_BURST_READ = 0x3C, ARDUCAM_FIFO_READ = 0x3D, ARDUCAM_READ_FW_VERSION = 0x40, @@ -63,8 +62,8 @@ camera_id_t getSelectedCamera(void) { return selectedCamera; } // CS assumed to be asserted static obc_error_code_t arducamTransmitOpcode(opcode_t opcode) { - obc_error_code_t errCode; - return LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, opcode)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, opcode)); + return OBC_ERR_CODE_SUCCESS; } obc_error_code_t arducamReadTestReg(uint8_t *buffer) { @@ -407,8 +406,7 @@ obc_error_code_t resetCPLD(void) { RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cameraCS[selectedCamera])); LOG_IF_ERROR_CODE(arducamTransmitOpcode(ARDUCAM_RESET_CPLD)); if (errCode == OBC_ERR_CODE_SUCCESS) { - LOG_IF_ERROR_CODE( - spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, 0)); + LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, 0)); } // Reset overwritten error code prevCode = errCode; @@ -434,7 +432,7 @@ obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t *regDat) { obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], size_t reglistLen) { obc_error_code_t errCode; - for (int i = 0; i < reglistLen; i++) { + for (size_t i = 0; i < reglistLen; i++) { RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(reglist[i].reg, reglist[i].val)); } diff --git a/obc/app/drivers/arducam/arducam.h b/obc/app/drivers/arducam/arducam.h index 20f6ba37d..2a4e57087 100644 --- a/obc/app/drivers/arducam/arducam.h +++ b/obc/app/drivers/arducam/arducam.h @@ -230,4 +230,4 @@ obc_error_code_t camReadSensorReg16_8(uint32_t regID, uint8_t* regDat); * @param reglist List of registers and data to write * @return Error code indicating if the writes were successful */ -obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], uint16_t reglistLen); +obc_error_code_t camWriteSensorRegs16_8(const sensor_config_t reglist[], size_t reglistLen); diff --git a/obc/app/drivers/arducam/camera_reg.c b/obc/app/drivers/arducam/camera_reg.c new file mode 100644 index 000000000..92bdfa5ea --- /dev/null +++ b/obc/app/drivers/arducam/camera_reg.c @@ -0,0 +1,99 @@ +#include +#include +#include "obc_i2c_io.h" +#include "obc_spi_io.h" +#include "obc_errors.h" +#include "obc_logging.h" +#include "obc_board_config.h" + +#include "ov5642_reg.h" +#include "camera_reg.h" + +#define CAM_I2C_WR_ADDR 0x3C +#define CAM_I2C_RD_ADDR 0x3C + +#define TCA_I2C_ADDR 0x70 + +#define I2C_MUTEX_TIMEOUT portMAX_DELAY +#define I2C_TRANSFER_TIMEOUT pdMS_TO_TICKS(100) + +static cam_settings_t cam_config[] = { + [PRIMARY] = {.spi_config = {.CS_HOLD = false, .WDEL = false, .DFSEL = CAM_SPI_DATA_FORMAT, .CSNR = SPI_CS_NONE}, + .cs_num = CAM_CS_1}, + [SECONDARY] = {.spi_config = {.CS_HOLD = false, .WDEL = false, .DFSEL = CAM_SPI_DATA_FORMAT, .CSNR = SPI_CS_NONE}, + .cs_num = CAM_CS_2}, +}; + +obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam) { + obc_error_code_t errCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + addr = addr | 0x80; + uint8_t tx[2] = {addr, data}; + errCode = spiTransmitBytes(CAM_SPI_REG, &cam_config[cam].spi_config, tx, 2); + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + return errCode; +} + +obc_error_code_t camReadReg(uint8_t addr, uint8_t *rx_data, camera_t cam) { + obc_error_code_t errCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + addr = addr & 0x7F; + errCode = spiTransmitByte(CAM_SPI_REG, &cam_config[cam].spi_config, addr); + if (!errCode) { + errCode = spiReceiveByte(CAM_SPI_REG, &cam_config[cam].spi_config, rx_data); + } + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + return errCode; +} + +obc_error_code_t camWriteByte(uint8_t byte, camera_t cam) { + obc_error_code_t errCode; + RETURN_IF_ERROR_CODE(assertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + errCode = spiTransmitByte(CAM_SPI_REG, &cam_config[cam].spi_config, byte); + RETURN_IF_ERROR_CODE(deassertChipSelect(CAM_SPI_PORT, cam_config[cam].cs_num)); + return errCode; +} + +obc_error_code_t camReadByte(uint8_t *byte, camera_t cam) { + return spiReceiveByte(CAM_SPI_REG, &cam_config[cam].spi_config, byte); +} + +obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat) { + uint8_t reg_tx_data[3] = {(regID >> 8), (regID & 0x00FF), regDat}; + return i2cSendTo(CAM_I2C_WR_ADDR, 3, reg_tx_data, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); +} + +obc_error_code_t camReadSensorReg16_8(uint8_t regID, uint8_t *regDat) { + // Todo: regID is byteswapped for some reason so 0x3138 needs to be input as 0x3831 + obc_error_code_t errCode; + RETURN_IF_ERROR_CODE(i2cSendTo(0x3C, 2, ®ID, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); + RETURN_IF_ERROR_CODE(i2cReceiveFrom(0x3C, 1, regDat, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT)); + return errCode; +} + +obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen) { + obc_error_code_t errCode; + + for (int i = 0; i < reglistLen; i++) { + RETURN_IF_ERROR_CODE(camWriteSensorReg16_8(reglist[i].reg, reglist[i].val)); + } + + return OBC_ERR_CODE_SUCCESS; +} + +obc_error_code_t tcaSelect(camera_t cam) { + uint8_t tca = 0; + if (cam == PRIMARY) { + tca = (1 << 0); + } else { + tca = (1 << 1); + } + return i2cSendTo(TCA_I2C_ADDR, 1, &tca, I2C_MUTEX_TIMEOUT, I2C_TRANSFER_TIMEOUT); +} + +uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam) { + uint8_t temp; + camReadReg(addr, &temp, cam); + temp = temp & (1 << bit); + return temp; +} diff --git a/obc/app/drivers/arducam/camera_reg.h b/obc/app/drivers/arducam/camera_reg.h new file mode 100644 index 000000000..910e8452a --- /dev/null +++ b/obc/app/drivers/arducam/camera_reg.h @@ -0,0 +1,96 @@ +#pragma once + +#include "stdint.h" +#include "obc_spi_io.h" +#include "ov5642_reg.h" +#include "obc_board_config.h" + +/** + * @enum camera_t + * @brief Primary or secondary camera. + * + * Enum containing camera identifiers. + */ +typedef enum { PRIMARY, SECONDARY } camera_t; + +/** + * @struct camera_settings_t + * @brief Camera settings struct + * + * Holds the settings for each camera. + */ +typedef struct { + spiDAT1_t spi_config; + uint8_t cs_num; +} cam_settings_t; + +/** + * @brief Write to a camera register over SPI + * @param addr Register address to write to + * @param data Data to send + * @param cam Camera identifier + * @return Error code indicating if the write was successful + */ +obc_error_code_t camWriteReg(uint8_t addr, uint8_t data, camera_t cam); + +/** + * @brief Read a camera register over SPI + * @param addr Register address to read from + * @param rx_data Buffer to store received data + * @param cam Camera identifier + * @return Error code indicating if the read was successful + */ +obc_error_code_t camReadReg(uint8_t regID, uint8_t* regDat, camera_t cam); + +/** + * @brief Write one byte to a camera over SPI + * @param byte Camera settings struct + * @param cam Camera identifier + * @return Error code + */ +obc_error_code_t camWriteByte(uint8_t byte, camera_t cam); + +/** + * @brief Read one byte to a camera over SPI, does not handle CS assertion + * @param byte Camera settings struct + * @param cam Camera identifier + * @return Error code + */ +obc_error_code_t camReadByte(uint8_t* byte, camera_t cam); + +/** + * @brief Read 8 bits from a 16 bit register over I2C + * @param regID Register address to write to + * @param regDat Data to send + * @return Error code indicating if the write was successful + */ +obc_error_code_t camWriteSensorReg16_8(uint32_t regID, uint8_t regDat); + +/** + * @brief Write 8 bits to a 16 bit register over I2C + * @param regID Register address to read from + * @param regDat Buffer to store received data + * @return Error code indicating if the read was successful + */ +obc_error_code_t camReadSensorReg16_8(uint8_t regID, uint8_t* regDat); + +/** + * @brief Write to a list of registers over I2C + * @param reglist List of registers and data to write + * @return Error code indicating if the writes were successful + */ +obc_error_code_t camWriteSensorRegs16_8(const sensor_reg_t reglist[], uint16_t reglistLen); + +/** + * @brief Select an I2C port on the TCA9458a multiplexer + * @param tca Port number to select + * @return Error code indicating if an ACK was received + */ +obc_error_code_t tcaSelect(camera_t cam); + +/** + * @brief Read one bit from a register over SPI + * @param addr Address to read from + * @param bit Bit to read + */ +uint8_t getBit(uint8_t addr, uint8_t bit, camera_t cam); diff --git a/obc/app/drivers/arducam/image_processing.c b/obc/app/drivers/arducam/image_processing.c new file mode 100644 index 000000000..c874d5af0 --- /dev/null +++ b/obc/app/drivers/arducam/image_processing.c @@ -0,0 +1,28 @@ +#include "image_processing.h" + +/** + * @brief Find the brightest pixel in an image packet + * @param packet The image packet to search through + * @param x The x coordinate of the brightest pixel + * @param y The y coordinate of the brightest pixel + * @param brightess The brightness of the brightest pixel + * @param packetStartY The y coordinate of the top left corner of the packet, the width of the packet is assumed to be + * the width of the image + */ +obc_error_code_t findBrightestPixelInPacket(image_t *packet, uint16_t *x, uint16_t *y, uint8_t *brightness, + uint16_t packetStartY) { + if (packet == NULL || x == NULL || y == NULL || brightness == NULL) { + return OBC_ERR_CODE_INVALID_ARG; + } + for (uint16_t i = 0; i < packet->height; i++) { + for (uint16_t j = 0; j < packet->width; j++) { + uint8_t pixel = packet->data[(i * packet->width) + j]; + if (pixel > *brightness) { + *brightness = pixel; + *x = j; + *y = i + packetStartY; + } + } + } + return OBC_ERR_CODE_SUCCESS; +} diff --git a/obc/app/drivers/arducam/image_processing.h b/obc/app/drivers/arducam/image_processing.h new file mode 100644 index 000000000..5f4f30a2e --- /dev/null +++ b/obc/app/drivers/arducam/image_processing.h @@ -0,0 +1,38 @@ +#pragma once + +#include "obc_errors.h" + +#include +#include + +/** + * @brief A struct to store an image + * @param width The width of the image + * @param height The height of the image + * @param data The image data + */ +typedef struct image_t { + uint16_t width; + uint16_t height; + uint8_t *data; +} image_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Find the brightest pixel in an image packet + * @param packet The image packet to search through + * @param x The x coordinate of the brightest pixel + * @param y The y coordinate of the brightest pixel + * @param brightess The brightness of the brightest pixel + * @param packetStartY The y coordinate of the top left corner of the packet, the width of the packet is assumed to be + * the width of the image + */ +obc_error_code_t findBrightestPixelInPacket(image_t *packet, uint16_t *x, uint16_t *y, uint8_t *brightness, + uint16_t packetStartY); + +#ifdef __cplusplus +} +#endif diff --git a/obc/app/drivers/arducam/ov5642_reg.c b/obc/app/drivers/arducam/ov5642_reg.c new file mode 100644 index 000000000..2b590dcc5 --- /dev/null +++ b/obc/app/drivers/arducam/ov5642_reg.c @@ -0,0 +1,192 @@ +#include +#include "ov5642_reg.h" + +// Configuration for the host preview +static sensor_reg_t OV5642_QVGA_Preview[PREVIEW_CONFIG_LEN] = { + {0x3103, 0x93}, {0x3008, 0x82}, {0x3017, 0x7f}, {0x3018, 0xfc}, {0x3810, 0xc2}, {0x3615, 0xf0}, {0x3000, 0x00}, + {0x3001, 0x00}, {0x3002, 0x5c}, {0x3003, 0x00}, {0x3004, 0xff}, {0x3005, 0xff}, {0x3006, 0x43}, {0x3007, 0x37}, + {0x3011, 0x08}, {0x3010, 0x10}, {0x460c, 0x22}, {0x3815, 0x04}, {0x370c, 0xa0}, {0x3602, 0xfc}, {0x3612, 0xff}, + {0x3634, 0xc0}, {0x3613, 0x00}, {0x3605, 0x7c}, {0x3621, 0x09}, {0x3622, 0x60}, {0x3604, 0x40}, {0x3603, 0xa7}, + {0x3603, 0x27}, {0x4000, 0x21}, {0x401d, 0x22}, {0x3600, 0x54}, {0x3605, 0x04}, {0x3606, 0x3f}, {0x3c01, 0x80}, + {0x5000, 0x4f}, {0x5020, 0x04}, {0x5181, 0x79}, {0x5182, 0x00}, {0x5185, 0x22}, {0x5197, 0x01}, {0x5001, 0xff}, + {0x5500, 0x0a}, {0x5504, 0x00}, {0x5505, 0x7f}, {0x5080, 0x08}, {0x300e, 0x18}, {0x4610, 0x00}, {0x471d, 0x05}, + {0x4708, 0x06}, {0x3808, 0x02}, {0x3809, 0x80}, {0x380a, 0x01}, {0x380b, 0xe0}, {0x380e, 0x07}, {0x380f, 0xd0}, + {0x501f, 0x00}, {0x5000, 0x4f}, {0x4300, 0x30}, {0x3503, 0x07}, {0x3501, 0x73}, {0x3502, 0x80}, {0x350b, 0x00}, + {0x3503, 0x07}, {0x3824, 0x11}, {0x3501, 0x1e}, {0x3502, 0x80}, {0x350b, 0x7f}, {0x380c, 0x0c}, {0x380d, 0x80}, + {0x380e, 0x03}, {0x380f, 0xe8}, {0x3a0d, 0x04}, {0x3a0e, 0x03}, {0x3818, 0xc1}, {0x3705, 0xdb}, {0x370a, 0x81}, + {0x3801, 0x80}, {0x3621, 0x87}, {0x3801, 0x50}, {0x3803, 0x08}, {0x3827, 0x08}, {0x3810, 0x40}, {0x3804, 0x05}, + {0x3805, 0x00}, {0x5682, 0x05}, {0x5683, 0x00}, {0x3806, 0x03}, {0x3807, 0xc0}, {0x5686, 0x03}, {0x5687, 0xbc}, + {0x3a00, 0x78}, {0x3a1a, 0x05}, {0x3a13, 0x30}, {0x3a18, 0x00}, {0x3a19, 0x7c}, {0x3a08, 0x12}, {0x3a09, 0xc0}, + {0x3a0a, 0x0f}, {0x3a0b, 0xa0}, {0x350c, 0x07}, {0x350d, 0xd0}, {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x00}, + {0x350a, 0x00}, {0x350b, 0x00}, {0x3503, 0x00}, {0x528a, 0x02}, {0x528b, 0x04}, {0x528c, 0x08}, {0x528d, 0x08}, + {0x528e, 0x08}, {0x528f, 0x10}, {0x5290, 0x10}, {0x5292, 0x00}, {0x5293, 0x02}, {0x5294, 0x00}, {0x5295, 0x02}, + {0x5296, 0x00}, {0x5297, 0x02}, {0x5298, 0x00}, {0x5299, 0x02}, {0x529a, 0x00}, {0x529b, 0x02}, {0x529c, 0x00}, + {0x529d, 0x02}, {0x529e, 0x00}, {0x529f, 0x02}, {0x3030, 0x0b}, {0x3a02, 0x00}, {0x3a03, 0x7d}, {0x3a04, 0x00}, + {0x3a14, 0x00}, {0x3a15, 0x7d}, {0x3a16, 0x00}, {0x3a00, 0x78}, {0x3a08, 0x09}, {0x3a09, 0x60}, {0x3a0a, 0x07}, + {0x3a0b, 0xd0}, {0x3a0d, 0x08}, {0x3a0e, 0x06}, {0x5193, 0x70}, {0x589b, 0x04}, {0x589a, 0xc5}, {0x401e, 0x20}, + {0x4001, 0x42}, {0x401c, 0x04}, {0x528a, 0x01}, {0x528b, 0x04}, {0x528c, 0x08}, {0x528d, 0x10}, {0x528e, 0x20}, + {0x528f, 0x28}, {0x5290, 0x30}, {0x5292, 0x00}, {0x5293, 0x01}, {0x5294, 0x00}, {0x5295, 0x04}, {0x5296, 0x00}, + {0x5297, 0x08}, {0x5298, 0x00}, {0x5299, 0x10}, {0x529a, 0x00}, {0x529b, 0x20}, {0x529c, 0x00}, {0x529d, 0x28}, + {0x529e, 0x00}, {0x529f, 0x30}, {0x5282, 0x00}, {0x5300, 0x00}, {0x5301, 0x20}, {0x5302, 0x00}, {0x5303, 0x7c}, + {0x530c, 0x00}, {0x530d, 0x0c}, {0x530e, 0x20}, {0x530f, 0x80}, {0x5310, 0x20}, {0x5311, 0x80}, {0x5308, 0x20}, + {0x5309, 0x40}, {0x5304, 0x00}, {0x5305, 0x30}, {0x5306, 0x00}, {0x5307, 0x80}, {0x5314, 0x08}, {0x5315, 0x20}, + {0x5319, 0x30}, {0x5316, 0x10}, {0x5317, 0x00}, {0x5318, 0x02}, {0x5402, 0x3f}, {0x5403, 0x00}, {0x3406, 0x00}, + {0x5180, 0xff}, {0x5181, 0x52}, {0x5182, 0x11}, {0x5183, 0x14}, {0x5184, 0x25}, {0x5185, 0x24}, {0x5186, 0x06}, + {0x5187, 0x08}, {0x5188, 0x08}, {0x5189, 0x7c}, {0x518a, 0x60}, {0x518b, 0xb2}, {0x518c, 0xb2}, {0x518d, 0x44}, + {0x518e, 0x3d}, {0x518f, 0x58}, {0x5190, 0x46}, {0x5191, 0xf8}, {0x5192, 0x04}, {0x5193, 0x70}, {0x5194, 0xf0}, + {0x5195, 0xf0}, {0x5196, 0x03}, {0x5197, 0x01}, {0x5198, 0x04}, {0x5199, 0x12}, {0x519a, 0x04}, {0x519b, 0x00}, + {0x519c, 0x06}, {0x519d, 0x82}, {0x519e, 0x00}, {0x5025, 0x80}, {0x5583, 0x40}, {0x5584, 0x40}, {0x5580, 0x02}, + {0x5000, 0xcf}, {0x3710, 0x10}, {0x3632, 0x51}, {0x3702, 0x10}, {0x3703, 0xb2}, {0x3704, 0x18}, {0x370b, 0x40}, + {0x370d, 0x03}, {0x3631, 0x01}, {0x3632, 0x52}, {0x3606, 0x24}, {0x3620, 0x96}, {0x5785, 0x07}, {0x3a13, 0x30}, + {0x3600, 0x52}, {0x3604, 0x48}, {0x3606, 0x1b}, {0x370d, 0x0b}, {0x370f, 0xc0}, {0x3709, 0x01}, {0x3823, 0x00}, + {0x5007, 0x00}, {0x5009, 0x00}, {0x5011, 0x00}, {0x5013, 0x00}, {0x519e, 0x00}, {0x5086, 0x00}, {0x5087, 0x00}, + {0x5088, 0x00}, {0x5089, 0x00}, {0x302b, 0x00}, {0x3808, 0x01}, {0x3809, 0x40}, {0x380a, 0x00}, {0x380b, 0xf0}, + {0x3a00, 0x78}, {0x5001, 0xFF}, {0x5583, 0x50}, {0x5584, 0x50}, {0x5580, 0x02}, {0x3c01, 0x80}, {0x3c00, 0x04}, + + {0x5800, 0x48}, {0x5801, 0x31}, {0x5802, 0x21}, {0x5803, 0x1b}, {0x5804, 0x1a}, {0x5805, 0x1e}, {0x5806, 0x29}, + {0x5807, 0x38}, {0x5808, 0x26}, {0x5809, 0x17}, {0x580a, 0x11}, {0x580b, 0xe}, {0x580c, 0xd}, {0x580d, 0xe}, + {0x580e, 0x13}, {0x580f, 0x1a}, {0x5810, 0x15}, {0x5811, 0xd}, {0x5812, 0x8}, {0x5813, 0x5}, {0x5814, 0x4}, + {0x5815, 0x5}, {0x5816, 0x9}, {0x5817, 0xd}, {0x5818, 0x11}, {0x5819, 0xa}, {0x581a, 0x4}, {0x581b, 0x0}, + {0x581c, 0x0}, {0x581d, 0x1}, {0x581e, 0x6}, {0x581f, 0x9}, {0x5820, 0x12}, {0x5821, 0xb}, {0x5822, 0x4}, + {0x5823, 0x0}, {0x5824, 0x0}, {0x5825, 0x1}, {0x5826, 0x6}, {0x5827, 0xa}, {0x5828, 0x17}, {0x5829, 0xf}, + {0x582a, 0x9}, {0x582b, 0x6}, {0x582c, 0x5}, {0x582d, 0x6}, {0x582e, 0xa}, {0x582f, 0xe}, {0x5830, 0x28}, + {0x5831, 0x1a}, {0x5832, 0x11}, {0x5833, 0xe}, {0x5834, 0xe}, {0x5835, 0xf}, {0x5836, 0x15}, {0x5837, 0x1d}, + {0x5838, 0x6e}, {0x5839, 0x39}, {0x583a, 0x27}, {0x583b, 0x1f}, {0x583c, 0x1e}, {0x583d, 0x23}, {0x583e, 0x2f}, + {0x583f, 0x41}, {0x5840, 0xe}, {0x5841, 0xc}, {0x5842, 0xd}, {0x5843, 0xc}, {0x5844, 0xc}, {0x5845, 0xc}, + {0x5846, 0xc}, {0x5847, 0xc}, {0x5848, 0xd}, {0x5849, 0xe}, {0x584a, 0xe}, {0x584b, 0xa}, {0x584c, 0xe}, + {0x584d, 0xe}, {0x584e, 0x10}, {0x584f, 0x10}, {0x5850, 0x11}, {0x5851, 0xa}, {0x5852, 0xf}, {0x5853, 0xe}, + {0x5854, 0x10}, {0x5855, 0x10}, {0x5856, 0x10}, {0x5857, 0xa}, {0x5858, 0xe}, {0x5859, 0xe}, {0x585a, 0xf}, + {0x585b, 0xf}, {0x585c, 0xf}, {0x585d, 0xa}, {0x585e, 0x9}, {0x585f, 0xd}, {0x5860, 0xc}, {0x5861, 0xb}, + {0x5862, 0xd}, {0x5863, 0x7}, {0x5864, 0x17}, {0x5865, 0x14}, {0x5866, 0x18}, {0x5867, 0x18}, {0x5868, 0x16}, + {0x5869, 0x12}, {0x586a, 0x1b}, {0x586b, 0x1a}, {0x586c, 0x16}, {0x586d, 0x16}, {0x586e, 0x18}, {0x586f, 0x1f}, + {0x5870, 0x1c}, {0x5871, 0x16}, {0x5872, 0x10}, {0x5873, 0xf}, {0x5874, 0x13}, {0x5875, 0x1c}, {0x5876, 0x1e}, + {0x5877, 0x17}, {0x5878, 0x11}, {0x5879, 0x11}, {0x587a, 0x14}, {0x587b, 0x1e}, {0x587c, 0x1c}, {0x587d, 0x1c}, + {0x587e, 0x1a}, {0x587f, 0x1a}, {0x5880, 0x1b}, {0x5881, 0x1f}, {0x5882, 0x14}, {0x5883, 0x1a}, {0x5884, 0x1d}, + {0x5885, 0x1e}, {0x5886, 0x1a}, {0x5887, 0x1a}, + + {0x5180, 0xff}, {0x5181, 0x52}, {0x5182, 0x11}, {0x5183, 0x14}, {0x5184, 0x25}, {0x5185, 0x24}, {0x5186, 0x14}, + {0x5187, 0x14}, {0x5188, 0x14}, {0x5189, 0x69}, {0x518a, 0x60}, {0x518b, 0xa2}, {0x518c, 0x9c}, {0x518d, 0x36}, + {0x518e, 0x34}, {0x518f, 0x54}, {0x5190, 0x4c}, {0x5191, 0xf8}, {0x5192, 0x04}, {0x5193, 0x70}, {0x5194, 0xf0}, + {0x5195, 0xf0}, {0x5196, 0x03}, {0x5197, 0x01}, {0x5198, 0x05}, {0x5199, 0x2f}, {0x519a, 0x04}, {0x519b, 0x00}, + {0x519c, 0x06}, {0x519d, 0xa0}, {0x519e, 0xa0}, + + {0x528a, 0x00}, {0x528b, 0x01}, {0x528c, 0x04}, {0x528d, 0x08}, {0x528e, 0x10}, {0x528f, 0x20}, {0x5290, 0x30}, + {0x5292, 0x00}, {0x5293, 0x00}, {0x5294, 0x00}, {0x5295, 0x01}, {0x5296, 0x00}, {0x5297, 0x04}, {0x5298, 0x00}, + {0x5299, 0x08}, {0x529a, 0x00}, {0x529b, 0x10}, {0x529c, 0x00}, {0x529d, 0x20}, {0x529e, 0x00}, {0x529f, 0x30}, + {0x5282, 0x00}, {0x5300, 0x00}, {0x5301, 0x20}, {0x5302, 0x00}, {0x5303, 0x7c}, {0x530c, 0x00}, {0x530d, 0x10}, + {0x530e, 0x20}, {0x530f, 0x80}, {0x5310, 0x20}, {0x5311, 0x80}, {0x5308, 0x20}, {0x5309, 0x40}, {0x5304, 0x00}, + {0x5305, 0x30}, {0x5306, 0x00}, {0x5307, 0x80}, {0x5314, 0x08}, {0x5315, 0x20}, {0x5319, 0x30}, {0x5316, 0x10}, + {0x5317, 0x00}, {0x5318, 0x02}, + + {0x5380, 0x01}, {0x5381, 0x00}, {0x5382, 0x00}, {0x5383, 0x1f}, {0x5384, 0x00}, {0x5385, 0x06}, {0x5386, 0x00}, + {0x5387, 0x00}, {0x5388, 0x00}, {0x5389, 0xE1}, {0x538A, 0x00}, {0x538B, 0x2B}, {0x538C, 0x00}, {0x538D, 0x00}, + {0x538E, 0x00}, {0x538F, 0x10}, {0x5390, 0x00}, {0x5391, 0xB3}, {0x5392, 0x00}, {0x5393, 0xA6}, {0x5394, 0x08}, + + {0x5480, 0x0c}, {0x5481, 0x18}, {0x5482, 0x2f}, {0x5483, 0x55}, {0x5484, 0x64}, {0x5485, 0x71}, {0x5486, 0x7d}, + {0x5487, 0x87}, {0x5488, 0x91}, {0x5489, 0x9a}, {0x548A, 0xaa}, {0x548B, 0xb8}, {0x548C, 0xcd}, {0x548D, 0xdd}, + {0x548E, 0xea}, {0x548F, 0x1d}, {0x5490, 0x05}, {0x5491, 0x00}, {0x5492, 0x04}, {0x5493, 0x20}, {0x5494, 0x03}, + {0x5495, 0x60}, {0x5496, 0x02}, {0x5497, 0xB8}, {0x5498, 0x02}, {0x5499, 0x86}, {0x549A, 0x02}, {0x549B, 0x5B}, + {0x549C, 0x02}, {0x549D, 0x3B}, {0x549E, 0x02}, {0x549F, 0x1C}, {0x54A0, 0x02}, {0x54A1, 0x04}, {0x54A2, 0x01}, + {0x54A3, 0xED}, {0x54A4, 0x01}, {0x54A5, 0xC5}, {0x54A6, 0x01}, {0x54A7, 0xA5}, {0x54A8, 0x01}, {0x54A9, 0x6C}, + {0x54AA, 0x01}, {0x54AB, 0x41}, {0x54AC, 0x01}, {0x54AD, 0x20}, {0x54AE, 0x00}, {0x54AF, 0x16}, {0x54B0, 0x01}, + {0x54B1, 0x20}, {0x54B2, 0x00}, {0x54B3, 0x10}, {0x54B4, 0x00}, {0x54B5, 0xf0}, {0x54B6, 0x00}, {0x54B7, 0xDF}, + {0x5402, 0x3f}, {0x5403, 0x00}, + + {0x5500, 0x10}, {0x5502, 0x00}, {0x5503, 0x06}, {0x5504, 0x00}, {0x5505, 0x7f}, + + {0x5025, 0x80}, {0x3a0f, 0x30}, {0x3a10, 0x28}, {0x3a1b, 0x30}, {0x3a1e, 0x28}, {0x3a11, 0x61}, {0x3a1f, 0x10}, + {0x5688, 0xfd}, {0x5689, 0xdf}, {0x568a, 0xfe}, {0x568b, 0xef}, {0x568c, 0xfe}, {0x568d, 0xef}, {0x568e, 0xaa}, + {0x568f, 0xaa}, +}; + +// Switch to JPEG +static sensor_reg_t OV5642_JPEG_Capture_QSXGA[JPEG_CONFIG_LEN] = { + // OV5642_ QSXGA _YUV7.5 fps + // 24 MHz input clock, 24Mhz pclk + // jpeg mode 7.5fps + + {0x3503, 0x07}, // AEC Manual Mode Control + {0x3000, 0x00}, // SYSTEM RESET00 + {0x3001, 0x00}, // Reset for Individual Block + {0x3002, 0x00}, // Reset for Individual Block + {0x3003, 0x00}, // Reset for Individual Block + {0x3005, 0xff}, // Clock Enable Control + {0x3006, 0xff}, // Clock Enable Control + {0x3007, 0x3f}, // Clock Enable Control + {0x350c, 0x07}, // AEC VTS Output high bits + {0x350d, 0xd0}, // AEC VTS Output low bits + {0x3602, 0xe4}, // Analog Control Registers + {0x3612, 0xac}, // Analog Control Registers + {0x3613, 0x44}, // Analog Control Registers + {0x3621, 0x27}, // Array Control 01 + {0x3622, 0x08}, // Analog Control Registers + {0x3623, 0x22}, // Analog Control Registers + {0x3604, 0x60}, // Analog Control Registers + {0x3705, 0xda}, // Analog Control Registers + {0x370a, 0x80}, // Analog Control Registers + {0x3801, 0x8a}, // HS + {0x3803, 0x0a}, // VS + {0x3804, 0x0a}, // HW + {0x3805, 0x20}, // HW + {0x3806, 0x07}, // VH + {0x3807, 0x98}, // VH + {0x3808, 0x0a}, // DVPHO + {0x3809, 0x20}, // DVPHO + {0x380a, 0x07}, // DVPVO + {0x380b, 0x98}, // DVPVO + {0x380c, 0x0c}, // HTS + {0x380d, 0x80}, // HTS + {0x380e, 0x07}, // VTS + {0x380f, 0xd0}, // VTS + {0x3810, 0xc2}, {0x3815, 0x44}, {0x3818, 0xc8}, // Mirror NO, Compression enable + {0x3824, 0x01}, // RSV + {0x3827, 0x0a}, // RSV + {0x3a00, 0x78}, // AEC System Control 0 + {0x3a0d, 0x10}, // 60 Hz Max Bands in One Frame + {0x3a0e, 0x0d}, // 50 Hz Max Bands in One Frame + {0x3a10, 0x32}, // Stable Range Low Limit (enter) + {0x3a1b, 0x3c}, // Stable Range High Limit (go out) + {0x3a1e, 0x32}, // Stable Range Low Limit (go out) + {0x3a11, 0x80}, // Step Manual Mode, Fast Zone High Limit + {0x3a1f, 0x20}, // Step Manual Mode, Fast Zone Low Limit + {0x3a00, 0x78}, // AEC System Control 0 + {0x460b, 0x35}, // RSV VFIFO Control 0B + {0x471d, 0x00}, // DVP CONTROL 1D + {0x4713, 0x03}, // COMPRESSION MODE SELECT mode3 + {0x471c, 0x50}, // RSV + {0x5682, 0x0a}, // AVG X END + {0x5683, 0x20}, // AVG X END + {0x5686, 0x07}, // AVG Y END + {0x5687, 0x98}, // AVG Y END + {0x5001, 0x4f}, // ISP CONTROL 01, UV adjust/Line stretch/UV average/Color matrix/AWB enable + {0x589b, 0x00}, // RSV + {0x589a, 0xc0}, // RSV + {0x4407, 0x08}, // COMPRESSION CTRL07 Bit[5:0]: Quantization scale 0x02 + {0x589b, 0x00}, // RSV + {0x589a, 0xc0}, // RSV + {0x3002, 0x0c}, // Reset for Individual Block, Reset SFIFO/compression + {0x3002, 0x00}, // Reset for Individual Block + {0x3503, 0x00}, // AEC Manual Mode Control, Auto enable + {0x5025, 0x80}, {0x3a0f, 0x48}, {0x3a10, 0x40}, {0x3a1b, 0x4a}, {0x3a1e, 0x3e}, {0x3a11, 0x70}, {0x3a1f, 0x20}, +}; + +// Switch to lowest resolution +static sensor_reg_t OV5642_320x240[RES_320_240_CONFIG_LEN] = { + {0x3800, 0x1}, {0x3801, 0xa8}, {0x3802, 0x0}, {0x3803, 0xA}, {0x3804, 0xA}, {0x3805, 0x20}, {0x3806, 0x7}, + {0x3807, 0x98}, {0x3808, 0x1}, {0x3809, 0x40}, {0x380a, 0x0}, {0x380b, 0xF0}, {0x380c, 0xc}, {0x380d, 0x80}, + {0x380e, 0x7}, {0x380f, 0xd0}, {0x5001, 0x7f}, {0x5680, 0x0}, {0x5681, 0x0}, {0x5682, 0xA}, {0x5683, 0x20}, + {0x5684, 0x0}, {0x5685, 0x0}, {0x5686, 0x7}, {0x5687, 0x98}, {0x3801, 0xb0}, +}; + +sensor_reg_t* getCamConfig(cam_config_t config) { + switch (config) { + case OV5642_QVGA_Preview_Config: + return OV5642_QVGA_Preview; + case OV5642_JPEG_Capture_QSXGA_Config: + return OV5642_JPEG_Capture_QSXGA; + case OV5642_320x240_Config: + return OV5642_320x240; + default: + return NULL; // Invalid Config + } +} diff --git a/obc/app/drivers/arducam/ov5642_reg.h b/obc/app/drivers/arducam/ov5642_reg.h new file mode 100644 index 000000000..2162569da --- /dev/null +++ b/obc/app/drivers/arducam/ov5642_reg.h @@ -0,0 +1,31 @@ +#pragma once + +#include "stdint.h" + +#define PREVIEW_CONFIG_LEN 583 +#define JPEG_CONFIG_LEN 71 +#define RES_320_240_CONFIG_LEN 26 + +/** + * @struct sensor_reg_t + * @brief Sensor reg struct, reg is the address to write to and val is the value to write + */ +typedef struct { + uint16_t reg; + uint8_t val; +} sensor_reg_t; + +/** + * @enum cam_config_t + * @brief Configuration array names to be called with getCamConfig(). + * + * Configuration array names. + */ +typedef enum { OV5642_QVGA_Preview_Config, OV5642_JPEG_Capture_QSXGA_Config, OV5642_320x240_Config } cam_config_t; + +/** + * @brief Access camera configuration arrays + * @param config Camera config array name + * @return Pointer to config array + */ +sensor_reg_t* getCamConfig(cam_config_t config); diff --git a/obc/app/modules/camera_mgr/CMakeLists.txt b/obc/app/modules/camera_mgr/CMakeLists.txt new file mode 100644 index 000000000..21f871366 --- /dev/null +++ b/obc/app/modules/camera_mgr/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.15) + +target_include_directories(${OUT_FILE_NAME} PUBLIC + include +) + +target_sources(${OUT_FILE_NAME} PUBLIC + source/arducam.c + source/camera_reg.c + source/ov5642_reg.c + source/payload_manager.c +) diff --git a/obc/examples/test_app_cc1120_spi/cc1120_spi_tests.c b/obc/examples/test_app_cc1120_spi/cc1120_spi_tests.c new file mode 100644 index 000000000..520d2e0a8 --- /dev/null +++ b/obc/examples/test_app_cc1120_spi/cc1120_spi_tests.c @@ -0,0 +1,95 @@ +#include "cc1120_spi_tests.h" +#include "cc1120_spi.h" +#include "cc1120_defs.h" +#include "cc1120_mcu.h" +#include + +uint8_t CC1120_REGS_DEFAULTS[CC1120_REGS_STD_SPACE_SIZE] = { + CC1120_DEFAULTS_IOCFG3, CC1120_DEFAULTS_IOCFG2, + CC1120_DEFAULTS_IOCFG1, CC1120_DEFAULTS_IOCFG0, + CC1120_DEFAULTS_SYNC3, CC1120_DEFAULTS_SYNC2, + CC1120_DEFAULTS_SYNC1, CC1120_DEFAULTS_SYNC0, + CC1120_DEFAULTS_SYNC_CFG1, CC1120_DEFAULTS_SYNC_CFG0, + CC1120_DEFAULTS_DEVIATION_M, CC1120_DEFAULTS_MODCFG_DEV_E, + CC1120_DEFAULTS_DCFILT_CFG, CC1120_DEFAULTS_PREAMBLE_CFG1, + CC1120_DEFAULTS_PREAMBLE_CFG0, CC1120_DEFAULTS_FREQ_IF_CFG, + CC1120_DEFAULTS_IQIC, CC1120_DEFAULTS_CHAN_BW, + CC1120_DEFAULTS_MDMCFG1, CC1120_DEFAULTS_MDMCFG0, + CC1120_DEFAULTS_SYMBOL_RATE2, CC1120_DEFAULTS_SYMBOL_RATE1, + CC1120_DEFAULTS_SYMBOL_RATE0, CC1120_DEFAULTS_AGC_REF, + CC1120_DEFAULTS_AGC_CS_THR, CC1120_DEFAULTS_AGC_GAIN_ADJUST, + CC1120_DEFAULTS_AGC_CFG3, CC1120_DEFAULTS_AGC_CFG2, + CC1120_DEFAULTS_AGC_CFG1, CC1120_DEFAULTS_AGC_CFG0, + CC1120_DEFAULTS_FIFO_CFG, CC1120_DEFAULTS_DEV_ADDR, + CC1120_DEFAULTS_SETTLING_CFG, CC1120_DEFAULTS_FS_CFG, + CC1120_DEFAULTS_WOR_CFG1, CC1120_DEFAULTS_WOR_CFG0, + CC1120_DEFAULTS_WOR_EVENT0_MSB, CC1120_DEFAULTS_WOR_EVENT0_LSB, + CC1120_DEFAULTS_PKT_CFG2, CC1120_DEFAULTS_PKT_CFG1, + CC1120_DEFAULTS_PKT_CFG0, CC1120_DEFAULTS_RFEND_CFG1, + CC1120_DEFAULTS_RFEND_CFG0, CC1120_DEFAULTS_PA_CFG2, + CC1120_DEFAULTS_PA_CFG1, CC1120_DEFAULTS_PA_CFG0, + CC1120_DEFAULTS_PKT_LEN}; + +/** + * @brief E2E test for SPI read function. + * Reads through all registers up to the extended register space, + * and compares values to default values. + * Burst reads all the values and compares them to the default values. + * Burst reads FREQ registers in extended address space and compares them to defaults. + * + * @return OBC_ERROR_CODE_SUCCESS - If all registers are read correctly and have the right value. + * @return An error code - If any register does not have the expected value, + * or status byte is invalid. + */ +obc_error_code_t cc1120TestSpiRead(void) { + obc_error_code_t errCode; + uint8_t addr = 0x00U; + uint8_t data; + + uint8_t burstData[CC1120_REGS_EXT_ADDR]; + errCode = cc1120ReadSpi(addr, burstData, CC1120_REGS_EXT_ADDR); + + LOG_IF_ERROR_CODE(errCode); + RETURN_IF_ERROR_CODE(errCode); + + if (memcmp(CC1120_REGS_DEFAULTS, burstData, CC1120_REGS_EXT_ADDR)) { + errCode = OBC_ERR_CODE_CC1120_TEST_FAILURE; + LOG_ERROR_CODE(errCode); + return errCode; + } + + if (errCode == OBC_ERR_CODE_SUCCESS) { + errCode = cc1120ReadExtAddrSpi(CC1120_REGS_EXT_MARCSTATE, &data, 1); + + LOG_IF_ERROR_CODE(errCode); + RETURN_IF_ERROR_CODE(errCode); + + if (data != 0x41U) { + errCode = OBC_ERR_CODE_CC1120_TEST_FAILURE; + LOG_ERROR_CODE(errCode); + return errCode; + } + } + + if (errCode == OBC_ERR_CODE_SUCCESS) { + uint8_t extBurstData[3]; + uint8_t expected[3] = {0x00U, 0x00U, 0x00U}; + errCode = cc1120ReadExtAddrSpi(CC1120_REGS_EXT_FREQ2, extBurstData, 3); + + if (errCode != OBC_ERR_CODE_SUCCESS) { + errCode = OBC_ERR_CODE_CC1120_TEST_FAILURE; + LOG_ERROR_CODE(errCode); + return errCode; + } + + if (memcmp(extBurstData, expected, 3)) { + errCode = OBC_ERR_CODE_CC1120_TEST_FAILURE; + LOG_ERROR_CODE(errCode); + return errCode; + } + } + + if (errCode == OBC_ERR_CODE_SUCCESS) LOG_INFO("CC1120 SPI read test passed.\n"); + + return errCode; +} diff --git a/obc/examples/test_app_cc1120_spi/cc1120_spi_tests.h b/obc/examples/test_app_cc1120_spi/cc1120_spi_tests.h new file mode 100644 index 000000000..af9a8138c --- /dev/null +++ b/obc/examples/test_app_cc1120_spi/cc1120_spi_tests.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "cc1120.h" +#include "obc_logging.h" + +/** + * @brief E2E test for SPI read function. + * Reads through all registers up to the extended register space, + * and compares values to default values. + * Burst reads all the values and compares them to the default values. + * Burst reads FREQ registers in extended address space and compares them to defaults. + * + * @return OBC_ERROR_CODE_SUCCESS - If all registers are read correctly and have the right value. + * @return An error code - If any register does not have the expected value, + * or status byte is invalid. + */ +obc_error_code_t cc1120TestSpiRead(void); diff --git a/obc/examples/test_app_cc1120_spi/main.c b/obc/examples/test_app_cc1120_spi/main.c new file mode 100644 index 000000000..c83d14e31 --- /dev/null +++ b/obc/examples/test_app_cc1120_spi/main.c @@ -0,0 +1,53 @@ +#include "obc_logging.h" +#include "obc_sci_io.h" +#include "obc_spi_io.h" + +#include "cc1120_spi_tests.h" + +#include "FreeRTOS.h" +#include "os_task.h" +#include "os_portable.h" + +#include +#include +#include +#include + +static TaskHandle_t testTaskHandle = NULL; +static StaticTask_t testTaskBuffer; +static StackType_t testTaskStack[1024U]; + +void initTestTask(void); +static void vTestTask(void* pvParameters); + +void initTestTask(void) { + ASSERT((testTaskStack != NULL) && (&testTaskBuffer != NULL)); + if (testTaskHandle == NULL) { + testTaskHandle = xTaskCreateStatic(vTestTask, "test task", 1024U, NULL, 1U, testTaskStack, &testTaskBuffer); + } +} + +static void vTestTask(void* pvParameters) { + // Run the E2E SPI read test + cc1120TestSpiRead(); + while (1) { + } +} + +int main(void) { + gioInit(); + sciInit(); + spiInit(); + + // Initialize logger + // initLogger(); + // logSetLevel(LOG_DEBUG); + + // Initialize bus mutexes + initSciMutex(); + initSpiMutex(); + + initTestTask(); + + vTaskStartScheduler(); +} diff --git a/obc/examples/test_app_rs/main.c b/obc/examples/test_app_rs/main.c new file mode 100644 index 000000000..bf9f91850 --- /dev/null +++ b/obc/examples/test_app_rs/main.c @@ -0,0 +1,63 @@ +#include "obc_spi_io.h" +#include "obc_print.h" +#include "obc_gs_fec.h" + +#include +#include +#include +#include +#include +#include + +static StaticTask_t taskBuffer; +static StackType_t taskStack[1024]; + +int vTask1(void *pvParameters) { + initRs(); + + packed_telem_packet_t telemData = {.data = {'-'}}; + + char *testData = "Hello world!"; + for (int i = 0; i < 13; i++) { + telemData.data[i] = (uint8_t)testData[i]; + } + + sciPrintf("Original data: %s\r\n", telemData.data); + + packed_rs_packet_t rsData = {.data = {0}}; + + rsEncode(&telemData.data, &rsData); + sciPrintf("Encoded data: %s\r\n", rsData.data); + rsData.data[0] = 'a'; // Simulate a bit flip + sciPrintf("Corrupted data: %s\r\n", rsData.data); + + uint8_t decodedData[RS_DECODED_SIZE] = {0}; + rsDecode(&rsData, decodedData, (uint8_t)RS_ENCODED_SIZE); + sciPrintf("Decoded data: %s\r\n", decodedData); + + destroyRs(); + while (1) + ; +} + +int main(void) { + // Initialize hardware. + gioInit(); + sciInit(); + spiInit(); + + // Initialize the SCI mutex. + initSciPrint(); + initSpiMutex(); + + sciPrintf("Starting RS Demo\r\n"); + + xTaskCreateStatic(vTask1, "RSDemo", 1024, NULL, 1, taskStack, &taskBuffer); + + vTaskStartScheduler(); + + while (1) + ; + + return 0; +} diff --git a/obc/shared/config/peripheral_config_definitions.cmake b/obc/shared/config/peripheral_config_definitions.cmake new file mode 100644 index 000000000..9a6466c4e --- /dev/null +++ b/obc/shared/config/peripheral_config_definitions.cmake @@ -0,0 +1,19 @@ +# board_config_definitions.cmake + +# Add Peripheral Configs + +# Add setup specific periperal configs globally here +# Ex: if you connected vn100, add -DCONFIG_VN100 inside set +set(COMMON_PERIPHERAL_CONFIG) + +# Board specifc configs - these should generally be kept as is unless the board is missing a component +if(BOARD_TYPE STREQUAL "RM46_LAUNCHPAD") + set(PERIPHERAL_CONFIG ${COMMON_PERIPHERAL_CONFIG}) +elseif(BOARD_TYPE STREQUAL "OBC_REVISION_1") + set(PERIPHERAL_CONFIG ${COMMON_PERIPHERAL_CONFIG} -DCONFIG_DS3232 -DCONFIG_SD_CARD -DCONFIG_FRAM -DCONFIG_LM75BD) +elseif(BOARD_TYPE STREQUAL "OBC_REVISION_2") + set(PERIPHERAL_CONFIG ${COMMON_PERIPHERAL_CONFIG} -DCONFIG_DS3232 -DCONFIG_SD_CARD -DCONFIG_FRAM -DCONFIG_LM75BD -DCONFIG_TPL5010) + +else() + message(FATAL_ERROR "Invalid BOARD_TYPE: ${BOARD_TYPE}. Board config not defined") +endif() From a20f7be315335dbb4e87365a90a97a2a18de5ddd Mon Sep 17 00:00:00 2001 From: tangerine238 Date: Thu, 7 Nov 2024 10:13:35 -0500 Subject: [PATCH 18/18] maybe fixed? --- obc/app/drivers/arducam/arducam.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/obc/app/drivers/arducam/arducam.c b/obc/app/drivers/arducam/arducam.c index 307f5d032..1a389f3e0 100644 --- a/obc/app/drivers/arducam/arducam.c +++ b/obc/app/drivers/arducam/arducam.c @@ -62,8 +62,9 @@ camera_id_t getSelectedCamera(void) { return selectedCamera; } // CS assumed to be asserted static obc_error_code_t arducamTransmitOpcode(opcode_t opcode) { + obc_error_code_t errCode; LOG_IF_ERROR_CODE(spiTransmitByte(CAM_SPI_REG, &arducamSPIDataFmt, opcode)); - return OBC_ERR_CODE_SUCCESS; + return errCode; } obc_error_code_t arducamReadTestReg(uint8_t *buffer) {