//Lucas Holt & Matt Halpern Camera TCM8230MD initialization and Capture //This code will initialize a TCM8230MD to capture pictures with a resolution of 128x94 (Oled on LMS1968 is 128x94) //The frame rate is set up for 1.875FPS /* PLEASE READ A PWM is used to provide the TCM8230MD with a clock I2C is used to issue initialization commands to the camera The TCM8230MD has 4 signals that are used to pass a camera frame from it to the LMS1968 (Vsync, Hsyc, Dclk, DataBus(1 Byte). A frame is composed of 263 lines. 96 of these lines are active with this initialization setup. 167 of the lines are inactive. For implementation with the LMS1968 only 94 of these 96 active lines can be used. Each line has 1560 cycles of Dclk. Only 256 of these Dclk cycles are active. This is because each pixel contains two bytes of data, and because the resolution of this camera is 128X96 there are 128 pixels. Recap 1 Frame= 263(lines) X 1560(dclkCycles/line)= 410280 cycles of dclk Active lines = 96 2 of these active lines are ignored because of limitations on the LMS968 Active dclks per line = 128 (pixels) X 2 bytes per pixel= 256 cycles of dclk The rising edge of Vsync signals the beginning of the frame The rising edge of Hsync signals the beginning of a line The falling edge of Dclk signals that the DataBus is read to be read (port D 1 Byte) */ /* This example accompanies the book Embedded Systems: Real-Time Operating Systems for the Arm Cortex-M3, Volume 3, ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2012 Program 6.4, section 6.7 Copyright 2012 by Jonathan W. Valvano, valvano@mail.utexas.edu You may use, edit, run or distribute this file as long as the above copyright notice remains THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. For more information about my classes, my research, and my books, see http://users.ece.utexas.edu/~valvano/ */ #include "camera.h" #include "PWM.h" #include "I2C.h" //gpio clock gating #define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108)) //gpio ports //port d #define GPIO_PORTD_DIR_R (*((volatile unsigned long *)0x40007400)) #define GPIO_PORTD_DEN_R (*((volatile unsigned long *)0x4000751C)) #define GPIO_PORTD_DATA_R (*((volatile unsigned long *)0x400073FC)) #define GPIO_PORTD_D0_R (*((volatile unsigned long *)0x40007004)) #define GPIO_PORTD_D2_R (*((volatile unsigned long *)0x40007010)) #define GPIO_PORTD_D3_R (*((volatile unsigned long *)0x40007020)) //port a #define GPIO_PORTA_DATA_R (*((volatile unsigned long *)0x400043FC)) #define GPIO_PORTA_DIR_R (*((volatile unsigned long *)0x40004400)) #define GPIO_PORTA_DEN_R (*((volatile unsigned long *)0x4000451C)) #define GPIO_PORTA_A2_R (*((volatile unsigned long *)0x40004010)) #define GPIO_PORTA_A3_R (*((volatile unsigned long *)0x40004020)) #define GPIO_PORTA_A4_R (*((volatile unsigned long *)0x40004040)) __asm void Delay2(unsigned long ulCount) { subs r0, #1 bne Delay2 bx lr } unsigned char tempLine[256]; //used to capture a line of color before it is processed into grayscale int LineNumber = 0; // two pixels per byte, 4 bit grey scale // resolution to 128(columns)x96(rows) unsigned char Camera_Picture[6016]; //------------Camera_Init------------ // Initialize camera //initialize the TCM8230MD, EXTCLK (PWM), I2C bus void Camera_Init(void){ SYSCTL_RCGC2_R |= 0x09; //gating for port A and D PWM1_Init(1); //external clk init to send initialization commands //camera requires a clk input of 6.25MHZ to properly recieve I2C commands //This clk speed will be reduced after initialization Delay2(50); I2C_Init(); //i2c init //enable port D for collecting pixel data from camera GPIO_PORTD_DIR_R &= 0x00; //port D all inputs GPIO_PORTD_DEN_R |=0xFF; //enable all 8 pins //enable port d to recieve frame,line,pixel control signals from camera GPIO_PORTA_DIR_R &=~0x1C; //make A4, A3, A2 inputs (DCLK, HS, and VS respectivly GPIO_PORTA_DEN_R |= 0x1C; //enable Dclk, HS, and VS Delay2(1000); //write to camera control adress 0x02 (dclk divide, and camera refresh rate) I2C_Send2(0x3C,0x02,0xC0); //This enables the camera to output the data at a frequency of (extclk/4) //for this implementation extclk=3.125MHZ //so dclk= .78125MHZ Delay2(50); //write to camera control adress 0x03 (camera on, picture resolution, pixel color format, color/black&white I2C_Send2(0x3C,0x03,0x22); //Turns on camera //set resolution to 128(columns)x96(rows) //set pixel format to RGB565 //color mode Delay2(50); //write to camera control address 0x1E (preline codes, hsync blanking control) I2C_Send2(0x3C,0x1E,0x48); //turn off all preline codes //set hsync to go low after 256 counts of dclk PWM1_Init(2); //external clk init for data send //intitialize the pwm to produce a 3.125MHZ clk with a duty cycle of 50% Delay2(1000); //debug } //------------Camera_Capture------------ // Take a picture void Camera_Capture(void){ int flag= 0; //flag used for conversion from clor to grayscale int hsink_count=0; //counter hsync<94(number of lines in a frame) int pixel_count=0; //pixel_count<256 (number of bytes per line) int temp_count=0; //counter used for processing from color to greyscale temp_count<256 int frameStorage_count=0; //keeps track of number of pixels in final frame array frameStorage_count<94X128<6016 unsigned char x=0; //first byte of a pixel unsigned char y=0; //second byte of a pixel unsigned char red=0; //amount of red in the photo unsigned char green=0; //amount of green in the photo unsigned char blue=0; //amount of blue in the photo unsigned char store_char=0; //byte to be stored into final display array int temp=0; //used during processing from color to greyscale //Begining of Frame capture while(GPIO_PORTA_A4_R==0x10){}; //wait while Vsync is high just in case u entered in the middle of a fram while(GPIO_PORTA_A4_R==0x00){}; //wait while Vsync is low while(hsink_count<94){ //capture 94 lines while(pixel_count<256){ //capture 256 bytes per line tempLine[pixel_count]= GPIO_PORTD_DATA_R; //read the data bus pixel_count++; while(GPIO_PORTA_A2_R == 0x00){} //wait while Dclk is low to avoid a double capture //this also re sycronizes the capture with Dclk } while(temp_count<256){ //Process all 256 bytes of color into 64 bytes of greyscale x = tempLine[temp_count]; //msb 15:8 of color 15:0 of a pixel y = tempLine[temp_count+1]; //lsb 7:0 of color 15:0 of a pixel //color format is RGB 565 //original color data is split up into 3 seperate items //necessary because rgb 565 weights green higher than red and blue red = x >>3; green=(x&0x07)+(y>>5); blue = y&0x1F; //add all of the colors up temp= red+green+blue; //max value of temp = 31(red) + 63(green) + 31(blue) = 125 temp= temp *2; //multiply by 2 because the gain of the camera is not properly calibrated //after the colors are added up the pixel value rarely exceeds 63 //multiply value by two to maximize pixel definition if(temp>127){ temp= 127; //if for some reason value is over 127 make it 127 to avoid loss of msb } temp=temp>>3; //left shift 3 so the pixel information is only 4bits (greyscale with 15 levels) //store 2 pixels per byte if(flag==0){ store_char = temp<<4; //store front pixel ins MSB is in 7:4 of final display byte flag = 1; } else if(flag==1){ store_char = store_char+temp; //store back pixel into LSB 3:0 of final display byte Camera_Picture[frameStorage_count] = store_char; //store two pixels are the same time frameStorage_count++; flag = 0; } temp_count+=2; } hsink_count++; temp_count = 0; pixel_count = 0; while(GPIO_PORTA_A3_R == 0x00){ //wait while the HSYNC remains low } } }