1 | #include "stm32f10x.h"
|
2 | #include <stdbool.h>
|
3 | #include <stdio.h>
|
4 | #include "main.h"
|
5 |
|
6 | // OV7670 i2c address
|
7 | #define OV7670I2C 0x21 // write 0x42 (<<1), read 0x43 (<<1,+0x01)
|
8 |
|
9 | // i2c bitbang pin defines
|
10 | #define SCLH GPIOB->BSRR = GPIO_Pin_6
|
11 | #define SCLL GPIOB->BRR = GPIO_Pin_6
|
12 | #define SDAH GPIOB->BSRR = GPIO_Pin_7
|
13 | #define SDAL GPIOB->BRR = GPIO_Pin_7
|
14 | #define SCLread GPIOB->IDR & GPIO_Pin_6
|
15 | #define SDAread GPIOB->IDR & GPIO_Pin_7
|
16 |
|
17 | GPIO_InitTypeDef GPIO_InitStructure;
|
18 |
|
19 | void main (void) {
|
20 |
|
21 | /* OV7670 connections
|
22 | * XCLK PB0 Min. 8 MHz for starting the cam; managed 9 MHz via TIM3 Channel 3 on PB0
|
23 | * VSYNC PB3 LOW marks start of frame; when HIGH then stop
|
24 | * HREF PB4 HIGH starts line; when LOW: line stop, don't read pixels
|
25 | * PCLK PB5 HIGH when pixel data valid
|
26 | * SCIO PB6 I2C1_SCL
|
27 | * SDIO PB7 I2C1_SDA
|
28 | * D0-D7 PB08-PB15 sample at rising edge of PCLK
|
29 | */
|
30 |
|
31 | SystemInit();
|
32 |
|
33 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
34 |
|
35 | // I2C1 interface to talk to OV7670 - bitbang :(
|
36 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
|
37 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
|
38 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
39 | GPIO_Init(GPIOB, &GPIO_InitStructure);
|
40 |
|
41 | // OV7670 data pins (PB8-PB15)
|
42 | GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
|
43 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
44 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
|
45 | GPIO_Init(GPIOB, &GPIO_InitStructure);
|
46 |
|
47 |
|
48 |
|
49 | // Start talking to OV7670
|
50 | sprintf(text, "Starting communication with OV7670.\n");
|
51 | uart_tx(text);
|
52 |
|
53 | uint8_t tempvalue = i2c_read(OV7670I2C, 0x11);
|
54 |
|
55 | sprintf(text, "Reading COM11 from I2C target: [%i].\n", tempvalue);
|
56 | uart_tx(text);
|
57 |
|
58 | i2c_write(OV7670I2C, 0x11, (tempvalue | 0b01001001)); // COM11 prescaler for PCLK=9
|
59 | sprintf(text, "Writing COM11 prescaler to I2C target: [%i].\n", (tempvalue | 0b01001001));
|
60 | uart_tx(text);
|
61 |
|
62 | sprintf(text, "Reading COM11 again from I2C target: [%i].\n", i2c_read(OV7670I2C, 0x11));
|
63 | uart_tx(text);
|
64 | }
|
65 |
|
66 | // ----------------------------------------------------------------------------
|
67 |
|
68 |
|
69 | // I2C support functions
|
70 |
|
71 | void i2c_delay(void)
|
72 | {
|
73 | // 72 MHz / 400 nops = 180KHz; 1600 ~= 45kHz
|
74 | for (int i=0; i<400; i++) {
|
75 | asm volatile ("nop");
|
76 | }
|
77 | }
|
78 |
|
79 | bool i2c_start(void)
|
80 | {
|
81 | SDAH;
|
82 | SCLH;
|
83 | i2c_delay();
|
84 | if (!(SDAread)) return false;
|
85 | SDAL;
|
86 | i2c_delay();
|
87 | if (SDAread) return false;
|
88 | SDAL;
|
89 | i2c_delay();
|
90 | Delay (2);
|
91 | return true;
|
92 | }
|
93 |
|
94 |
|
95 | void i2c_stop(void)
|
96 | {
|
97 | SCLL;
|
98 | i2c_delay();
|
99 | SDAL;
|
100 | i2c_delay();
|
101 | SCLH;
|
102 | i2c_delay();
|
103 | SDAH;
|
104 | i2c_delay();
|
105 | Delay (2);
|
106 | }
|
107 |
|
108 |
|
109 | void i2c_ack(void)
|
110 | {
|
111 | SCLL;
|
112 | i2c_delay();
|
113 | SDAL;
|
114 | i2c_delay();
|
115 | SCLH;
|
116 | i2c_delay();
|
117 | SCLL;
|
118 | i2c_delay();
|
119 | Delay (2);
|
120 | }
|
121 |
|
122 |
|
123 | void i2c_nack(void)
|
124 | {
|
125 | SCLL;
|
126 | i2c_delay();
|
127 | SDAH;
|
128 | i2c_delay();
|
129 | SCLH;
|
130 | i2c_delay();
|
131 | SCLL;
|
132 | i2c_delay();
|
133 | Delay (2);
|
134 | }
|
135 |
|
136 |
|
137 | bool i2c_waitack(void)
|
138 | {
|
139 | SCLL;
|
140 | i2c_delay();
|
141 | SDAH;
|
142 | i2c_delay();
|
143 | SCLH;
|
144 | i2c_delay();
|
145 | if(SDAread)
|
146 | {
|
147 | SCLL;
|
148 | Delay (2);
|
149 | }
|
150 | SCLL;
|
151 | Delay (2);
|
152 | }
|
153 |
|
154 |
|
155 | void i2c_send(uint8_t data) {
|
156 | Delay (2);
|
157 |
|
158 | for(int i=0; i<8; i++) {
|
159 | SCLL;
|
160 | i2c_delay();
|
161 | if (data & 0x80)
|
162 | SDAH;
|
163 | else SDAL;
|
164 | data<<=1;
|
165 | i2c_delay();
|
166 | SCLH;
|
167 | i2c_delay();
|
168 | }
|
169 | SCLL;
|
170 | }
|
171 |
|
172 | uint8_t i2c_receive(void) {
|
173 | uint8_t tempresult = 0;
|
174 |
|
175 | SDAH;
|
176 | for (int i=0; i<8; i++) {
|
177 | tempresult<<=1;
|
178 | SCLL;
|
179 | i2c_delay();
|
180 | SCLH;
|
181 | i2c_delay();
|
182 | if(SDAread)
|
183 | {
|
184 | tempresult|=0x01;
|
185 | }
|
186 | }
|
187 | SCLL;
|
188 | Delay (2);
|
189 |
|
190 | return (tempresult);
|
191 | }
|
192 |
|
193 | void i2c_write(int i2c_target, uint8_t address, uint8_t data) {
|
194 | if(!i2c_start()) {
|
195 | return;
|
196 | }
|
197 | i2c_send(i2c_target << 1);
|
198 | if(!i2c_waitack()) {
|
199 | i2c_stop();
|
200 | return;
|
201 | }
|
202 | i2c_send(address);
|
203 | i2c_waitack();
|
204 | i2c_send(data);
|
205 | i2c_waitack();
|
206 | i2c_stop();
|
207 | }
|
208 |
|
209 | uint8_t i2c_read(int i2c_target, uint8_t address) {
|
210 | int tempresult = 0;
|
211 |
|
212 | bool retry = true;
|
213 | int times =5;
|
214 | while (retry) {
|
215 | if(!i2c_start()) {
|
216 | return false;
|
217 | }
|
218 | i2c_send(i2c_target << 1);
|
219 | if(!i2c_waitack()) {
|
220 | i2c_stop();
|
221 | times--;
|
222 | if (times == 0) return false;
|
223 | } else retry = false;
|
224 | }
|
225 | i2c_send(address);
|
226 | i2c_waitack();
|
227 | i2c_stop();
|
228 | i2c_start();
|
229 | i2c_send(((i2c_target << 1)+1));
|
230 | i2c_waitack();
|
231 |
|
232 | tempresult = i2c_receive();
|
233 | i2c_nack();
|
234 | i2c_stop();
|
235 | return (tempresult);
|
236 | }
|