秋月電子で販売しているカメラモジュール(OV7670)をSTMマイコンで使ってみます.
カメラモジュールとの通信はSCCBというI2Cと同じような通信方式で行うことができます. 今回はSTMマイコンとカメラモジュールを接続してプロダクトIDを読むところまでします.
開発環境等
- Windows10
- Arduino IDE 1.8.12
- STM32F446RE Nucleoボード
- カメラモジュール(OV7670)
※Arduino IDEにはSTM32マイコンが扱えるようにボードを追加しています.
配線
マイコンのSDAピンとSCLピンをそれぞれカメラのSIO-DピンとSIO-Cピンに接続します. SDAとSCLは4.7kΩの抵抗でプルアップします.
また,カメラモジュールを動かすにはXCLKにクロックを供給する必要があります.
カメラモジュールのRESETピンはLOWで有効になるので,3.3Vに接続してHIGHの状態にします. 一方でPWDNピン(Power down)はHIGHで有効になるので,GNDに接続してLOWの状態にします.
Vccは3.3Vに接続し,GNDはGNDに接続します.
VREF1とVREF2はそれぞれGND間に0.1uFのコンデンサを接続しました.
STM32 | カメラ |
---|---|
SDA(PB9) | SIO-D |
SCL(PB8) | SIO-C |
PA8 | XCLK |
3.3V | RESET |
GND | PWDN |
3.3V | Vcc |
GND | GND |
秋月電子の販売ページにある「サンプルプログラム」をクリックするとZIPファイルがダウンロードできます. その中に「COMSカメラモジュール参考資料.pdf」というファイルがあります. PDFファイルには配線図が書いてあるのでそれも参考にしてください.
プログラム
mco_init()
関数でSTMマイコンのPA8ピンからクロックを供給する設定をしています. loop()
関数内ではレジスタアドレスを指定して値を読みだしています.
OV7670は0x42
でwrite,0x43
でreadできます. これは8bitでの表現になります. Arduinoでは下位1bitを無視して7bitとするので,指定する値は0x21
となります.
データシートを見るとOV7670は0x0a
を送ると,プロダクトIDを返してくれることがわかりました(上図の赤枠で囲ったところ). デフォルトでは0x76
が返ってくるみたいです. 下記コードを実行するとちゃんと0x76
が返ってくることが確認できました.
プログラム全体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <Wire.h>
void mco_init() {
// MCO1: PA8
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_4);
GPIO_InitTypeDef GPIO_InitStruct;
// Configure GPIO pin : PA8 MCO1
__GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Hello stm32!!!");
mco_init();
}
void loop() {
Wire.beginTransmission(0x21); // 0x42を右に1ビットシフトした値
Wire.write(0x12); // ソフトウェアリセット
Wire.write(0x80);
Wire.endTransmission();
delay(500); // リセット完了を待つ
Wire.beginTransmission(0x21);
Wire.write(0x0a); // read from reg 0x0a
Wire.endTransmission();
Wire.requestFrom(0x21, 1);
while (Wire.available() == 0); // 値が来るまで待つ
while (Wire.available()) {
Serial.println(Wire.read(), HEX);
}
}