Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: TSI USBDevice mbed-dev
Fork of SmartWheels by
Hardwares/ArduCAM.cpp
- Committer:
- hazheng
- Date:
- 2017-04-12
- Revision:
- 65:295c222fdf88
- Parent:
- 64:43ab429a37e0
- Child:
- 70:311d32a596db
File content as of revision 65:295c222fdf88:
#include "ArduCAM.h"
//#define SW_DEBUG
#include "GlobalVariable.h"
#include "SWCommon.h"
#include "CamRegBuf.h"
#include "ArduUTFT.h"
#include <string>
#define CAM_BLK_CAL_ACTIVE
//#define CAM_DISP_DEBUG
//#define CAM_DISP_DEBUG_CENTER
//#define CAM_DISP_IMG
#define IMG_PROC_SIGNAL 0xBB
#ifdef __cplusplus
extern "C" {
#endif
const static uint8_t CAM_BLK_CAL_LEFT = ((RESOLUTION_WIDTH / 2) - 1);
const static uint8_t CAM_BLK_CAL_RIGHT = ((RESOLUTION_WIDTH / 2) + 1);
const static uint8_t TERMINATE_WIDTH = static_cast<uint8_t>(RESOLUTION_WIDTH * 0.30f);
static DigitalOut cam_cs(PIN_ACC_CS, 1);
static uint8_t temp_mid_pos = RESOLUTION_WIDTH / 2;
static uint8_t black_calibrate = 70;
static volatile uint8_t centerLine[CAM_ROI_UPPER_LIMIT * 2];
static volatile uint8_t is_encounter_terminate = 0;
//static Thread * m_imgProcessThread = NULL;
//static Ticker m_tickerImgProc;
//void image_processing();
void cal_black_calibrate();
//void tick_image_proc();
inline void ardu_cam_spi_write_8(int address, int value)
{
// take the SS pin low to select the chip:
#ifdef SW_DEBUG
g_sw_spi_lock.lock();
#endif
cam_cs = 0;
// send in the address and value via SPI:
g_spi_port.write(address | 0x80);
g_spi_port.write(value);
// take the SS pin high to de-select the chip:
cam_cs = 1;
#ifdef SW_DEBUG
g_sw_spi_lock.unlock();
#endif
}
inline uint8_t ardu_cam_spi_read_8(int address)
{
// take the SS pin low to select the chip:
#ifdef SW_DEBUG
g_sw_spi_lock.lock();
#endif
cam_cs = 0;
// send in the address and value via SPI:
g_spi_port.write(address & 0x7F);
uint8_t value = static_cast<uint8_t>(g_spi_port.write(0x00));
// take the SS pin high to de-select the chip:
cam_cs = 1;
#ifdef SW_DEBUG
g_sw_spi_lock.unlock();
#endif
return value;
}
/*
inline void ardu_cam_spi_set_burst()
{
cam_cs = 0;
g_spi_port.write(BURST_FIFO_READ & 0x7F);
cam_cs = 1;
}
inline uint16_t ardu_cam_spi_burst_read_16()
{
cam_cs = 0;
uint16_t value = static_cast<uint16_t>(g_spi_port.write(0x00));
value = (value << 8) & 0xFF00;
value = value | static_cast<uint16_t>(g_spi_port.write(0x00));
cam_cs = 1;
return value;
}
*/
bool ardu_cam_init()
{
//char buf[20];
CamRegBuf * camReg = new CamRegBuf(g_core, CAM_SCCB_WRITE, CAM_SCCB_READ);
camReg->WriteRegSet(ResetProg);
wait_ms(10);
camReg->WriteRegSet(QVGA);
wait_ms(10);
#if defined(ARDUCAM_OV2640)
camReg->SCCBWrite(0xff, 0x01);
#endif
//uint8_t camVer = camReg->SCCBRead(CAM_PID_ADDR);
//sprintf(buf, "Cam VerH %#x", camVer);
//g_core.GetUSBServer().PushReliableMsg('D', buf);
//camVer = camReg->SCCBRead(CAM_VER_ADDR);
//sprintf(buf, "Cam VerL %#x", camVer);
//g_core.GetUSBServer().PushReliableMsg('D', buf);
delete camReg;
camReg = NULL;
uint8_t VerNum = ardu_cam_spi_read_8(0x40);
VerNum = ardu_cam_spi_read_8(0x40);
//sprintf(buf, "Ardu Ver %#x", VerNum);
//g_core.GetUSBServer().PushReliableMsg('D', buf);
ardu_cam_spi_write_8(ARDUCHIP_TEST1, ARDUCHIP_TEST_MSG);
uint8_t testV = ardu_cam_spi_read_8(ARDUCHIP_TEST1);
if(VerNum != ARDUCHIP_VER_NUM || testV != ARDUCHIP_TEST_MSG)
{
//g_core.GetUSBServer().PushReliableMsg('D', "CameraInit Fa");
return false;
}
//g_core.GetUSBServer().PushReliableMsg('D', "CameraInit Su");
//ardu_cam_set_mode(MCU2LCD_MODE);
ardu_cam_spi_write_8(ARDUCHIP_CAP_CTRL, 0x00);
//ardu_cam_start_capture();
//unsigned char tempV = ardu_cam_read_reg(ARDUCHIP_MODE);
//sprintf(buf, "Ardu Stat %#x", tempV);
//g_core.GetUSBServer().PushReliableMsg('D', buf);
//tempV = ardu_cam_read_reg(ARDUCHIP_CAP_CTRL);
//sprintf(buf, "Ardu FS1 %#x", tempV);
//g_core.GetUSBServer().PushReliableMsg('D', buf);
cal_black_calibrate();
//m_imgProcessThread = new Thread(osPriorityRealtime); //osPriorityAboveNormal //osPriorityHigh //osPriorityRealtime
//m_imgProcessThread->set_priority(osPriorityRealtime);
//m_imgProcessThread->start(callback(image_processing));
//m_tickerImgProc.attach(&tick_image_proc, 0.1f);
return true;
}
void ardu_cam_start_capture()
{
ardu_cam_spi_write_8(ARDUCHIP_FIFO, FIFO_CLEAR_MASK);
ardu_cam_spi_write_8(ARDUCHIP_FIFO, FIFO_START_MASK);
}
uint32_t ardu_cam_get_fifo_length()
{
uint32_t len1,len2,len3,length=0;
len1 = ardu_cam_spi_read_8(FIFO_SIZE1);
len2 = ardu_cam_spi_read_8(FIFO_SIZE2);
len3 = ardu_cam_spi_read_8(FIFO_SIZE3) & 0x07;
length = ((len3 << 16) | (len2 << 8) | len1) & 0x07ffff;
return length;
}
uint8_t ardu_cam_get_pixel()
{
uint16_t VH = ardu_cam_spi_read_8(SINGLE_FIFO_READ);
uint16_t VL = ardu_cam_spi_read_8(SINGLE_FIFO_READ);
//uint16_t VL = ardu_cam_spi_burst_read_16();
VL = (VL & 0x00FF) | ((VH << 8) & 0xFF00);
uint8_t ch = ((VL & 0xF800) >> 9);// << 2;
float pixel = (static_cast<float>(ch) * 0.21);
ch = ((VL & 0x07E0) >> 3);// << 2;
pixel += (static_cast<float>(ch) * 0.72);
ch = (VL & 0x001F) << 2;
pixel += (static_cast<float>(ch) * 0.07);
return static_cast<uint8_t>(pixel);
}
void ardu_cam_print_debug()
{
uint32_t len = ardu_cam_get_fifo_length();
//char buf[20];
//sprintf(buf, "Cam L %#x", len);
//g_core.GetUSBServer().PushReliableMsg('D', buf);
//if(len < (RESOLUTION_HEIGHT * RESOLUTION_WIDTH * 2))
// return;
//Begin output the picture
std::string lineBuf;
#if defined(MANUAL_REDUCE_RESULOTION_BY2)
lineBuf.resize((RESOLUTION_WIDTH / 2) + 1);
#else
lineBuf.resize(RESOLUTION_WIDTH + 1);
#endif
//ardu_cam_spi_set_burst();
//ardu_cam_get_pixel(); //Get the first dummy pixel
for (uint8_t i = 0; i < RESOLUTION_HEIGHT; ++i)
{
#if defined(MANUAL_REDUCE_RESULOTION_BY2)
lineBuf[0] = i / 2;
for (int j = 0; j < RESOLUTION_WIDTH; ++j)
{
if(i % 2 == 0 || j % 2 == 0)
{
ardu_cam_get_pixel();
}
else
{
lineBuf[(j / 2) + 1] = ardu_cam_get_pixel();
}
}
if(i % 2 == 0)
{
}
else
{
g_core.GetUSBServer().PushReliableMsg('P', lineBuf);
wait(0.35);
}
#else
lineBuf[0] = i;
for (int j = 0; j < RESOLUTION_WIDTH; ++j)
{
//uint8_t p = ardu_cam_get_pixel();
lineBuf[j + 1] = ardu_cam_get_pixel();
}
//g_core.GetUSBServer().PushReliableMsg('P', lineBuf);
wait(0.35);
#endif
}
}
uint8_t ardu_cam_is_capture_finished()
{
return (ardu_cam_spi_read_8(ARDUCHIP_TRIG) & CAP_DONE_MASK);
}
void cal_black_calibrate()
{
ardu_cam_start_capture();
while (!(ardu_cam_spi_read_8(ARDUCHIP_TRIG) & CAP_DONE_MASK));
float temp = 0.0f;
static uint16_t pixel = 0x00;
for (uint8_t j = 0; j < RESOLUTION_WIDTH; ++j)
{
pixel = static_cast<uint16_t>(ardu_cam_spi_read_8(SINGLE_FIFO_READ)) << 8;
pixel = pixel | ardu_cam_spi_read_8(SINGLE_FIFO_READ);
if(CAM_BLK_CAL_LEFT < j && j <= CAM_BLK_CAL_RIGHT)
{
temp += static_cast<uint8_t>((pixel >> 3) & 0x00FF);
}
}
temp = temp / (CAM_BLK_CAL_RIGHT - CAM_BLK_CAL_LEFT);
black_calibrate = temp * 0.7f;
}
inline void get_img_row_info(const uint8_t display, const uint8_t rowI, uint8_t * left, uint8_t * right, uint8_t* isBorderFound)
{
*left = 0;
*right = RESOLUTION_WIDTH;
*isBorderFound = BOTH_NOT_FOUND;
uint8_t isRightFound = 0;
static uint16_t pixel = 0x0000;
static uint8_t pGreen = 0x00;
for (uint8_t j = 0; j < RESOLUTION_WIDTH; ++j)
{
pixel = static_cast<uint16_t>(ardu_cam_spi_read_8(SINGLE_FIFO_READ)) << 8;
pixel = pixel | ardu_cam_spi_read_8(SINGLE_FIFO_READ);
pGreen = static_cast<uint8_t>((pixel & 0x07E0) >> 3);
if((pGreen < black_calibrate))
{
if(j < temp_mid_pos)
{
*isBorderFound = LEFT_FOUND;
*left = j;
#ifdef CAM_DISP_DEBUG
ardu_utft_write_DATA(0xF8, 0x00);
#endif
}
else if(!isRightFound)
{
*right = j;
isRightFound = 1;
#ifdef CAM_DISP_DEBUG
ardu_utft_write_DATA(0xF8, 0x00);
#endif
}
}
#ifdef CAM_DISP_DEBUG
else
{
ardu_utft_write_DATA(static_cast<uint8_t>(pixel >> 8), static_cast<uint8_t>(pixel));
}
#elif defined(CAM_DISP_IMG)
ardu_utft_write_DATA(static_cast<uint8_t>(pixel >> 8), static_cast<uint8_t>(pixel));
#endif
}
if(*isBorderFound == LEFT_FOUND && isRightFound)
{
*isBorderFound = BOTH_FOUND;
}
else if(isRightFound)
{
*isBorderFound = RIGHT_FOUND;
}
}
volatile const uint8_t* ardu_cam_get_center_array()
{
return centerLine;
}
void image_processing()
{
//while(true)
{
ardu_cam_start_capture();
while (!(ardu_cam_spi_read_8(ARDUCHIP_TRIG) & CAP_DONE_MASK));
temp_mid_pos = RESOLUTION_WIDTH / 2;
#ifdef CAM_BLK_CAL_ACTIVE
static float calTemp = 0.0f;
calTemp = 0.0f;
static uint16_t greenPixel = 0x00;
uint8_t isValid = 1;
for (uint8_t j = 0; j < RESOLUTION_WIDTH; ++j)
{
if(CAM_BLK_CAL_LEFT < j && j <= CAM_BLK_CAL_RIGHT)
{
greenPixel = static_cast<uint16_t>(ardu_cam_spi_read_8(SINGLE_FIFO_READ)) << 8;
greenPixel = greenPixel | ardu_cam_spi_read_8(SINGLE_FIFO_READ);
greenPixel = (greenPixel & 0x07E0) >> 3;
if(static_cast<uint8_t>(greenPixel) < black_calibrate)
{
isValid = 0;
}
calTemp += static_cast<uint8_t>(greenPixel);
}
else
{
ardu_cam_spi_read_8(SINGLE_FIFO_READ);
ardu_cam_spi_read_8(SINGLE_FIFO_READ);
}
}
if(isValid)
{
calTemp = calTemp / static_cast<float>(CAM_BLK_CAL_RIGHT - CAM_BLK_CAL_LEFT);
black_calibrate = static_cast<uint8_t>(calTemp * 0.7f);
}
#endif
//cal_black_calibrate();
uint8_t leftPos = 0;
uint8_t rightPos = 0;
uint8_t isBorderFound = BOTH_NOT_FOUND;
//is_encounter_terminate = 0;
for (uint8_t i = 0; i < CAM_ROI_UPPER_LIMIT; ++i)
/*{
for (uint8_t j = 0; j < RESOLUTION_WIDTH; ++j)
{
ardu_cam_spi_read_8(SINGLE_FIFO_READ);
ardu_cam_spi_read_8(SINGLE_FIFO_READ);
}
}*/
//for(uint8_t i = CAM_ROI_UPPER_LIMIT; i < (2 * CAM_ROI_UPPER_LIMIT); ++i)
{
#if defined(CAM_DISP_IMG) or defined(CAM_DISP_DEBUG)
ardu_utft_set_camimg_row(CAM_ROI_UPPER_LIMIT - i);
#endif
get_img_row_info(0, i, &leftPos, &rightPos, &isBorderFound);
temp_mid_pos = (leftPos + rightPos) / 2;
uint8_t dis_btw_left_right = rightPos - leftPos - 1;
if(dis_btw_left_right < TERMINATE_WIDTH)
{
is_encounter_terminate = 1;
}
#ifdef CAM_DISP_DEBUG_CENTER
ardu_utft_set_camimg_rowcol(CAM_ROI_UPPER_LIMIT - i, temp_mid_pos);
ardu_utft_write_DATA(0xF8, 0x00);
#endif
centerLine[CAM_ROI_UPPER_LIMIT - i - 1] = temp_mid_pos;
centerLine[(2 * CAM_ROI_UPPER_LIMIT) - i - 1] = isBorderFound;
}
//counter.Update();
//Thread::signal_wait(IMG_PROC_SIGNAL, osWaitForever);
}
}
void ardu_cam_display_img_utft()
{
ardu_cam_start_capture();
while (!(ardu_cam_spi_read_8(ARDUCHIP_TRIG) & CAP_DONE_MASK));
temp_mid_pos = RESOLUTION_WIDTH / 2;
for (uint8_t i = 0; i < CAM_ROI_UPPER_LIMIT; ++i)
{
ardu_utft_set_camimg_row(CAM_ROI_UPPER_LIMIT - i);
for (uint8_t j = 0; j < RESOLUTION_WIDTH; ++j)
{
uint8_t VH = ardu_cam_spi_read_8(SINGLE_FIFO_READ);
uint8_t VL = ardu_cam_spi_read_8(SINGLE_FIFO_READ);
ardu_utft_write_DATA(VH, VL);
}
}
}
uint8_t ardu_cam_get_is_encounter_terminate()
{
return is_encounter_terminate;
}
/*
void tick_image_proc()
{
m_imgProcessThread->signal_set(IMG_PROC_SIGNAL);
}
*/
#ifdef __cplusplus
}
#endif
