Add (not really working) camera interface

This commit is contained in:
fruchti 2018-08-23 11:17:49 +02:00
parent 8247add832
commit 116ab5d23b
7 changed files with 374 additions and 14 deletions

View file

@ -11,7 +11,8 @@
"stm32f100xb.h": "c",
"buildid.h": "c",
"font_arpegius_32.h": "c",
"font_arpegius_16.h": "c"
"font_arpegius_16.h": "c",
"debug.h": "c"
},
"C_Cpp.intelliSenseEngineFallback": "Enabled"
}

View file

@ -1 +1 @@
323
405

View file

@ -2,9 +2,6 @@
int main(void)
{
LTP1245_Init();
// LTP1245_FeedPaper(10);
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH = (GPIOC->CRH
@ -12,16 +9,24 @@ int main(void)
| (0x01 << (4 * PIN_LED - 32)) // Output, max. 10 MHz
;
char buff[30];
itoa(BUILD_NUMBER, buff, 10);
Camera_Init();
LTP1245_Init();
char buff[30] = "Build No. ";
itoa(BUILD_NUMBER, buff + strlen(buff), 10);
Print_Text(buff, &Messe_Duesseldorf_39);
// LTP1245_FeedPaper(10);
// Print_Text("Testy McTestFace", &Arpegius_32);
// Print_Text("123555bcD", &Messe_Duesseldorf_39);
Print_Text("This is a long line with very much text!", &Hannover_Messe_Serif_26);
LTP1245_FeedPaper(2);
strcpy(buff, "Line count: ");
extern int LineCount;
itoa(LineCount, buff + strlen(buff), 10);
Print_Text(buff, &Hannover_Messe_Serif_26);
LTP1245_FeedPaper(10);
LTP1245_Cut();
// LTP1245_FeedPaper(10);
// LTP1245_Cut();
for(;;)
{

View file

@ -8,6 +8,7 @@
#include "pinning.h"
#include "buildid.h"
#include "debug.h"
#include "ov7670.h"
#include "ltp1245.h"
#include "print.h"
#include "font_hannover_messe_serif_26.h"

347
src/ov7670.c Normal file
View file

@ -0,0 +1,347 @@
#include "ov7670.h"
#include "pinning.h"
#include "debug.h"
#define REG_GAIN 0x00
#define REG_BLUE 0x01
#define REG_RED 0x02
#define REG_VREF 0x03
#define REG_COM1 0x04
#define REG_BAVE 0x05
#define REG_GbAVE 0x06
#define REG_AECHH 0x07
#define REG_RAVE 0x08
#define REV_COM2 0x09
#define REG_PID 0x0a
#define REG_VER 0x0b
#define REG_COM3 0x0c
#define REG_COM4 0x0d
#define REG_COM5 0x0e
#define REG_COM6 0x0f
#define REG_AECH 0x10
#define REG_CLKRC 0x11
#define REG_COM7 0x12
#define REG_COM8 0x13
#define REG_COM9 0x14
#define REG_COM10 0x15
#define REG_HSTART 0x17
#define REG_HSTOP 0x18
#define REG_VSTRT 0x19
#define REG_VSTOP 0x1a
#define REG_PSHIFT 0x1b
#define REG_MIDH 0x1c
#define REG_MIDL 0x1d
#define REG_MVFP 0x1e
#define REG_LAEC 0x1f
#define REG_ADCCTR0 0x20
#define REG_ADCCTR1 0x21
#define REG_ADCCTR2 0x22
#define REG_ADCCTR3 0x23
#define REG_AEW 0x24
#define REG_AEB 0x25
#define REG_VPT 0x26
#define REG_BBIAS 0x27
#define REG_GbBIAS 0x28
#define REG_EXHCH 0x2a
#define REG_EXHCL 0x2b
#define REG_RBIAS 0x2c
#define REG_ADVFL 0x2d
#define REG_ADVFH 0x2e
#define REG_YAVE 0x2f
#define REG_HSYST 0x30
#define REG_HSYEN 0x31
#define REG_HREF 0x32
#define REG_CHLF 0x33
#define REG_ARBLM 0x34
#define REG_ADC 0x37
#define REG_ACOM 0x38
#define REG_OFON 0x39
#define REG_TSLB 0x3a
#define REG_COM11 0x3b
#define REG_COM12 0x3c
#define REG_COM13 0x3d
#define REG_COM14 0x3e
#define REG_EDGE 0x3f
#define REG_COM15 0x40
#define REG_COM16 0x41
#define REG_COM17 0x42
#define REG_REG4B 0x4b
#define REG_DNSTH 0x4c
#define REG_MTX1 0x4f
#define REG_MTX2 0x50
#define REG_MTX3 0x51
#define REG_MTX4 0x52
#define REG_MTX5 0x53
#define REG_MTX6 0x54
#define REG_BRIGHT 0x55
#define REG_CONTRAS 0x56
#define REG_CONTRAS_CENTER 0x57
#define REG_MTXS 0x58
#define REG_LCC1 0x62
#define REG_LCC2 0x63
#define REG_LCC3 0x64
#define REG_LCC4 0x65
#define REG_LCC5 0x66
#define REG_MANU 0x67
#define REG_MANV 0x68
#define REG_GFIX 0x69
#define REG_GGAIN 0x6a
#define REG_DBLV 0x6b
#define REG_AWBCTR3 0x6c
#define REG_AWBCTR2 0x6d
#define REG_AWBCTR1 0x6e
#define REG_AWBCTR0 0x6f
#define REG_SCALING_XSC 0x70
#define REG_SCALING_YSC 0x71
#define REG_SCALING_DCWCTR 0x72
#define REG_SCALING_PCLK_DIV 0x73
#define REG_REG74 0x74
#define REG_REG75 0x75
#define REG_REG76 0x76
#define REG_REG77 0x77
#define REG_SLOP 0x7a
#define REG_GAM1 0x7b
#define REG_GAM2 0x7c
#define REG_GAM3 0x7d
#define REG_GAM4 0x7e
#define REG_GAM5 0x7f
#define REG_GAM6 0x80
#define REG_GAM7 0x81
#define REG_GAM8 0x82
#define REG_GAM9 0x83
#define REG_GAM10 0x84
#define REG_GAM11 0x85
#define REG_GAM12 0x86
#define REG_GAM13 0x87
#define REG_GAM14 0x88
#define REG_GAM15 0x89
#define REG_RGB444 0x8c
#define REG_DM_LNL 0x92
#define REG_DM_LNH 0x93
#define REG_LCC6 0x94
#define REG_LCC7 0x95
#define REG_BD50ST 0x9d
#define REG_BD60ST 0x9e
#define REG_HAECC1 0x9f
#define REG_HAECC2 0xa0
#define REG_SCALING_PCLK_DELAY 0xa2
#define REG_NT_CTRL 0xa4
#define REG_BD50MAX 0xa5
#define REG_HAECC3 0xa6
#define REG_HAECC4 0xa7
#define REG_HAECC5 0xa8
#define REG_HAECC6 0xa9
#define REG_HAECC7 0xaa
#define REG_BD60MAX 0xab
#define REG_STR_OPT 0xac
#define REG_STR_R 0xad
#define REG_STR_G 0xae
#define REG_STR_B 0xaf
#define REG_ABLC1 0xb1
#define REG_THL_ST 0xb3
#define REG_THL_DLT 0xb5
#define REG_AD_CHB 0xbe
#define REG_AD_CHR 0xbf
#define REG_AD_CHGb 0xc0
#define REG_AD_CHGr 0xc1
#define REG_SATCR 0xc9
#define I2C_ADDRESS 0x42
uint8_t ImageBuffer[176 * 144 / 8];
static volatile int CurrentLine = 0;
uint8_t LineBuffer1[176];
uint8_t LineBuffer2[176];
int LineCount = 0;
static uint8_t ReadRegister(uint8_t reg)
{
while(I2C1->SR2 & I2C_SR2_BUSY);
I2C1->CR1 |= I2C_CR1_START;
while(~I2C1->SR1 & I2C_SR1_SB);
I2C1->DR = I2C_ADDRESS;
while(~I2C1->SR1 & I2C_SR1_ADDR);
I2C1->SR2; // Dummy read
I2C1->DR = reg; // Write the register number to be read
while(~I2C1->SR1 & (I2C_SR1_TXE | I2C_SR1_BTF));
I2C1->CR1 |= I2C_CR1_STOP;
// Read the register value
while(I2C1->SR2 & I2C_SR2_BUSY);
I2C1->CR1 |= I2C_CR1_START;
while(~I2C1->SR1 & I2C_SR1_SB);
I2C1->DR = I2C_ADDRESS | 1;
while(~I2C1->SR1 & I2C_SR1_ADDR);
I2C1->SR2; // Dummy read
I2C1->CR1 |= I2C_CR1_STOP;
while(~I2C1->SR1 & I2C_SR1_RXNE);
uint8_t data = I2C1->DR;
return data;
}
static void WriteRegister(uint8_t reg, uint8_t value)
{
while(I2C1->SR2 & I2C_SR2_BUSY);
I2C1->CR1 |= I2C_CR1_START;
while(~I2C1->SR1 & I2C_SR1_SB);
I2C1->DR = I2C_ADDRESS;
while(~I2C1->SR1 & I2C_SR1_ADDR);
I2C1->SR2; // Dummy read
I2C1->DR = reg; // Write the register number
while(~I2C1->SR1 & (I2C_SR1_TXE | I2C_SR1_BTF));
I2C1->DR = value; // Write the register value
while(~I2C1->SR1 & (I2C_SR1_TXE | I2C_SR1_BTF));
I2C1->CR1 |= I2C_CR1_STOP;
}
void Camera_Init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// Reset pin
GPIOB->CRH = (GPIOB->CRH
& ~(0x0f << (4 * PIN_CAMERA_RESET - 32)))
| (0x01 << (4 * PIN_CAMERA_RESET - 32)) // Output, max. 10 MHz
;
GPIOB->BRR = (1 << PIN_CAMERA_RESET);
GPIOB->BSRR = (1 << PIN_CAMERA_RESET);
// Enable MCO for camera main clock line (PLL / 2 -> 24 MHz)
RCC->CFGR |= RCC_CFGR_MCO;
GPIOA->CRH = (GPIOA->CRH
& ~(0x0f << (4 * PIN_CAMERA_MCLK - 32)))
| (0x0b << (4 * PIN_CAMERA_MCLK - 32)) // Output, max. 50 MHz
;
AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP;
// I2C interface for camera configuration
GPIOB->CRH = (GPIOB->CRH
& ~(0x0f << (4 * PIN_CAMERA_SCL - 32))
& ~(0x0f << (4 * PIN_CAMERA_SDA - 32)))
| (0x0e << (4 * PIN_CAMERA_SCL - 32)) // AF OD output, 2 MHz
| (0x0e << (4 * PIN_CAMERA_SDA - 32)) // AF OD output, 2 MHz
;
I2C1->CR1 = I2C_CR1_SWRST;
I2C1->CR1 = 0;
I2C1->CR2 = (24 << I2C_CR2_FREQ_Pos);
I2C1->CCR = I2C_CCR_FS | I2C_CCR_DUTY | (1 << I2C_CCR_CCR_Pos) | 5;
I2C1->CR1 = I2C_CR1_PE;
// Timer setup
AFIO->MAPR |= AFIO_MAPR_TIM3_REMAP_PARTIALREMAP;
GPIOB->CRL = (GPIOB->CRL
& ~(0x0f << (PIN_CAMERA_HSYNC * 4))
& ~(0x0f << (PIN_CAMERA_PCLK * 4)))
| (0x04 << (PIN_CAMERA_HSYNC * 4)) // Floating input
| (0x04 << (PIN_CAMERA_PCLK * 4)) // Floating input
;
GPIOA->CRH = (GPIOA->CRH
& ~(0x0f << (PIN_CAMERA_VSYNC * 4 - 32)))
| (0x04 << (PIN_CAMERA_VSYNC * 4 - 32)) // Floating input
;
// TIM1_CH2 is VSYNC
TIM1->PSC = 0;
TIM1->ARR = 65535;
TIM1->CCMR1 = TIM_CCMR1_CC2S_0;
TIM1->CCER = TIM_CCER_CC2E;
TIM1->DIER = TIM_DIER_CC2IE;
TIM1->CR1 = TIM_CR1_CEN;
NVIC_SetPriority(TIM1_CC_IRQn, 0);
NVIC_EnableIRQ(TIM1_CC_IRQn);
// TIM3_CH2 is HSYNC and should trigger an interrupt, while TIM3_CH1 is the
// pixel clock and should trigger DMA transfers
TIM3->PSC = 0;
TIM3->ARR = 1;
TIM3->CCMR1 = TIM_CCMR1_CC2S_0 | TIM_CCMR1_CC1S_0 | TIM_CCMR1_IC1PSC_0;
TIM3->CCER = TIM_CCER_CC2P | TIM_CCER_CC2E | TIM_CCER_CC1E | TIM_CCER_CC1P;
TIM3->DIER = TIM_DIER_CC2IE;
TIM3->CR1 = TIM_CR1_CEN;
NVIC_SetPriority(TIM3_IRQn, 0);
NVIC_EnableIRQ(TIM3_IRQn);
// Fetch GPIOA IDR lower byte
DMA1_Channel6->CMAR = (uint32_t)&(GPIOA->IDR);
// Startup delay
for(volatile int i = 0; i < 1000; i++);
// Camera configuration
ReadRegister(REG_PID);
// Disable timing resets
WriteRegister(REG_COM6, 0x00);
// Enable scaling
WriteRegister(REG_COM3, 0x08 | 0x04);
// Use QCIF output format
WriteRegister(REG_COM7, 0x08);
// Blank pixel clock during sync pulses
WriteRegister(REG_COM10, 0x20);
// Set clock prescaler to 2
WriteRegister(REG_CLKRC, 0x4 | 1);
// Enable pixel clock scaling
WriteRegister(REG_COM14, 0x10);
}
void TIM1_CC_IRQHandler(void)
{
// VSYNC
// GPIOC->BRR = (1 << PIN_LED);
LineCount = CurrentLine;
CurrentLine = 0;
// Dummy read
TIM1->CCR2;
TIM1->SR &= ~TIM_SR_CC2IF;
// GPIOC->BSRR = (1 << PIN_LED);
}
void TIM3_IRQHandler(void)
{
// HSYNC
GPIOC->BRR = (1 << PIN_LED);
TIM3->DIER &= ~TIM_DIER_CC1DE;
TIM3->SR &= ~TIM_SR_CC1IF;
DMA1_Channel6->CCR = 0;
DMA1_Channel6->CNDTR = sizeof(LineBuffer1);
if(CurrentLine & 1)
{
DMA1_Channel6->CMAR = (uint32_t)LineBuffer1;
}
else
{
DMA1_Channel6->CMAR = (uint32_t)LineBuffer2;
}
DMA1_Channel6->CCR = DMA_CCR_PL | DMA_CCR_MINC | DMA_CCR_EN;
TIM3->DIER |= TIM_DIER_CC1DE;
// ImageBuffer[0] = 0;
CurrentLine++;
// Dummy read
TIM3->CCR2;
TIM3->SR &= ~TIM_SR_CC2IF;
GPIOC->BSRR = (1 << PIN_LED);
}

6
src/ov7670.h Normal file
View file

@ -0,0 +1,6 @@
#pragma once
#include <stdlib.h>
#include "stm32f1xx.h"
void Camera_Init(void);

View file

@ -10,7 +10,7 @@
#define PIN_CAMERA_DB6 6 // PA6 - Camera data line 6
#define PIN_CAMERA_DB7 7 // PA7 - Camera data line 7
#define PIN_CAMERA_MCLK 8 // PA8 - Camera main clock (MCO/TIM1_CH1)
#define PIN_CAMERA_PCLK 9 // PA9 - Camera pixel clock (TIM1_CH2)
#define PIN_CAMERA_VSYNC 9 // PA9 - Camera VSYNC (TIM1_CH2)
#define PIN_STEPPER_AP 10 // PA10 - Stepper phase A positive
#define PIN_STEPPER_BP 11 // PA11 - Stepper phase B positive
#define PIN_STEPPER_AM 12 // PA12 - Stepper phase A negative
@ -21,7 +21,7 @@
#define PIN_VBATT 1 // PB1 - Battery monitor (ADC12_IN9)
#define PIN_SUPPLY 2 // PB2 - Voltage regulator enable
#define PIN_PAPER 3 // PB3 - Paper detect
#define PIN_CAMERA_VSYNC 4 // PB4 - Camera VSYNC (TIM3_CH1)
#define PIN_CAMERA_PCLK 4 // PB4 - Camera pixel clock (TIM3_CH1)
#define PIN_CAMERA_HSYNC 5 // PB5 - Camera VSYNC (TIM3_CH2)
#define PIN_HEAD 6 // PB6 - Head up sensor
#define PIN_PAPER_CUT 7 // PB7 - Paper cutter servo (TIM4_CH2)