parent
6ca974487f
commit
23be368b68
1 changed files with 98 additions and 36 deletions
134
src/main.c
134
src/main.c
|
|
@ -284,13 +284,14 @@ static void led_init() {
|
|||
|
||||
static void i2c_init(void);
|
||||
static void lcd_init(void);
|
||||
static void lcd_pex_set_noblock(uint8_t value);
|
||||
static void i2c_write(uint8_t addr, size_t n);
|
||||
static void i2c_nonblocking_mode(void);
|
||||
static void i2c_blocking_mode(void);
|
||||
static void lcd_tx_nibble(uint8_t value, uint8_t flags);
|
||||
static void lcd_pex_set(uint8_t value);
|
||||
static void lcd_poll(void);
|
||||
static void delay_us(int duration_us);
|
||||
static void lcd_command(uint8_t value);
|
||||
static void lcd_write(const char **buf);
|
||||
static void lcd_write_dma(const char **buf);
|
||||
|
||||
|
||||
/* https://www.lcd-module.de/eng/pdf/zubehoer/ks0066.pdf */
|
||||
|
|
@ -342,9 +343,8 @@ enum LCD_FUNCTION_Cmd {
|
|||
|
||||
struct {
|
||||
uint8_t buf[512];
|
||||
size_t bpos;
|
||||
size_t ndt;
|
||||
bool run;
|
||||
uint32_t cr2_buf;
|
||||
bool blocking;
|
||||
} st_i2c;
|
||||
|
||||
bool lcd_led;
|
||||
|
|
@ -353,12 +353,31 @@ void i2c_init() {
|
|||
memset(&st_i2c, 0, sizeof(st_i2c));
|
||||
SYSCFG->CFGR1 |= SYSCFG_CFGR1_I2C1_DMA_RMP | SYSCFG_CFGR1_TIM17_DMA_RMP2;
|
||||
|
||||
/* Magic value for 100kHz I2C @ 48MHz CLK. Fell out of STMCubeMX, then tweaked looking at an oscilloscope. I love
|
||||
* downloading 120MB of software to download another 100MB of software, only this time over unsecured HTTP, to
|
||||
* generate 3.5 bytes of configuration values using a Java(TM) GUI. */
|
||||
/* Magic value for 100kHz I2C @ 48MHz CLK. Fell out of STMCubeMX. I love downloading 120MB of software to download
|
||||
* another 100MB of software, only this time over unsecured HTTP, to generate 3.5 bytes of configuration values
|
||||
* using a Java(TM) GUI. */
|
||||
I2C1->TIMINGR = (0<<I2C_TIMINGR_PRESC_Pos) | (11<<I2C_TIMINGR_SCLDEL_Pos) | (0<<I2C_TIMINGR_SDADEL_Pos) |
|
||||
(51<<I2C_TIMINGR_SCLH_Pos) | (46<<I2C_TIMINGR_SCLL_Pos);
|
||||
I2C1->CR1 = I2C_CR1_PE;
|
||||
I2C1->CR1 = I2C_CR1_ERRIE | I2C_CR1_TXDMAEN | I2C_CR1_PE;
|
||||
|
||||
/* TIM1 for DMA timing */
|
||||
TIM17->PSC = 47;
|
||||
TIM17->ARR = 50;
|
||||
TIM17->DIER = TIM_DIER_UDE;
|
||||
TIM17->CR1 = TIM_CR1_CEN;
|
||||
|
||||
/* I2C1 TX */
|
||||
DMA1_Channel6->CCR = (0<<DMA_CCR_MSIZE_Pos) | (0<<DMA_CCR_PSIZE_Pos) | DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TEIE | DMA_CCR_TCIE;
|
||||
DMA1_Channel6->CPAR = (uint32_t)&(I2C1->TXDR);
|
||||
DMA1_Channel6->CMAR = (uint32_t)&st_i2c.buf;
|
||||
|
||||
/* I2C1 START trigger */
|
||||
DMA1_Channel7->CCR = (2<<DMA_CCR_MSIZE_Pos) | (2<<DMA_CCR_PSIZE_Pos) | DMA_CCR_DIR | DMA_CCR_TEIE;
|
||||
DMA1_Channel7->CPAR = (uint32_t)&(I2C1->CR2);
|
||||
DMA1_Channel7->CMAR = (uint32_t)&st_i2c.cr2_buf;
|
||||
|
||||
NVIC_EnableIRQ(DMA1_Channel4_5_6_7_IRQn);
|
||||
NVIC_EnableIRQ(I2C1_IRQn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -379,17 +398,13 @@ enum I2C1_Address {
|
|||
LCD_PEX_ADDR = 0x4E,
|
||||
};
|
||||
|
||||
void lcd_pex_set_noblock(uint8_t value) {
|
||||
void lcd_pex_set(uint8_t value) {
|
||||
if (lcd_led) {
|
||||
value |= B_LCD_LED;
|
||||
}
|
||||
|
||||
I2C1->TXDR = value;
|
||||
I2C1->CR2 = (1 << I2C_CR2_NBYTES_Pos) | I2C_CR2_AUTOEND | (LCD_PEX_ADDR << I2C_CR2_SADD_Pos) | I2C_CR2_START;
|
||||
}
|
||||
|
||||
void lcd_pex_set(uint8_t value) {
|
||||
lcd_pex_set_noblock(value);
|
||||
while (I2C1->ISR & I2C_ISR_BUSY || !(I2C1->ISR & I2C_ISR_TXE)) {
|
||||
/* do nothing. */
|
||||
}
|
||||
|
|
@ -414,29 +429,18 @@ void lcd_command(uint8_t value) {
|
|||
lcd_tx_nibble(value, 0);
|
||||
}
|
||||
|
||||
void lcd_poll() {
|
||||
if (!st_i2c.run) {
|
||||
return;
|
||||
void lcd_write_dma(const char **buf) {
|
||||
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
|
||||
DMA1_Channel7->CCR &= ~DMA_CCR_EN;
|
||||
while ((DMA1_Channel6->CCR & DMA_CCR_EN) | (DMA1_Channel7->CCR & DMA_CCR_EN)) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
if (!(I2C1->ISR & I2C_ISR_BUSY) && (12C1->ISR & I2C_ISR_TXE)) {
|
||||
I2C1->TXDR = st_i2c.txd[st_i2c.bpos];
|
||||
I2C1->CR2 = (1 << I2C_CR2_NBYTES_Pos) | I2C_CR2_AUTOEND | (LCD_PEX_ADDR << I2C_CR2_SADD_Pos) | I2C_CR2_START;
|
||||
st_i2c.bpos++;
|
||||
if (st_i2c.bpos == st_i2c.ndt) {
|
||||
st_i2c.run = false;
|
||||
st_i2c.bpos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lcd_write(const char **buf) {
|
||||
uint8_t line_offset[4] = {0, 64, 20, 84};
|
||||
uint8_t led = lcd_led ? B_LCD_LED : 0;
|
||||
|
||||
uint8_t *p = st_i2c.buf;
|
||||
for (size_t line=0; line<4; line++) {
|
||||
|
||||
uint8_t command = LCD_CMD_DDRAM_ADDR | line_offset[line];
|
||||
/* set address */
|
||||
*p++ = ((command>>4)<<4) | B_LCD_E | led;
|
||||
|
|
@ -458,13 +462,20 @@ void lcd_write(const char **buf) {
|
|||
*p++ = led;
|
||||
*p++ = led;
|
||||
|
||||
st_i2c.ndt = p - st_i2c.buf;
|
||||
st_i2c.bpos = 0;
|
||||
st_i2c.run = true;
|
||||
size_t n = p - st_i2c.buf;
|
||||
DMA1_Channel6->CNDTR = n;
|
||||
DMA1_Channel6->CCR |= DMA_CCR_TCIE;
|
||||
DMA1_Channel6->CCR |= DMA_CCR_EN;
|
||||
|
||||
st_i2c.cr2_buf = (1 << I2C_CR2_NBYTES_Pos) | I2C_CR2_AUTOEND | (LCD_PEX_ADDR << I2C_CR2_SADD_Pos) | I2C_CR2_START;
|
||||
DMA1_Channel7->CNDTR = n;
|
||||
DMA1_Channel7->CCR |= DMA_CCR_EN;
|
||||
}
|
||||
|
||||
void lcd_init() {
|
||||
lcd_led = false;
|
||||
i2c_init();
|
||||
i2c_blocking_mode();
|
||||
delay_us(40000);
|
||||
|
||||
lcd_tx_nibble(LCD_ENTER_4BIT, 0);
|
||||
|
|
@ -473,6 +484,47 @@ void lcd_init() {
|
|||
lcd_command(LCD_CMD_CLEAR);
|
||||
delay_us(2000);
|
||||
lcd_command(LCD_CMD_ENTRY_MODE | LCD_ENTRY_CUR_RIGHT);
|
||||
lcd_led = true;
|
||||
i2c_nonblocking_mode();
|
||||
}
|
||||
|
||||
void i2c_write(uint8_t addr, size_t n) {
|
||||
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
|
||||
while (DMA1_Channel6->CCR & DMA_CCR_EN) {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
DMA1_Channel6->CNDTR = n;
|
||||
DMA1_Channel6->CCR |= DMA_CCR_EN;
|
||||
|
||||
I2C1->CR2 = (n << I2C_CR2_NBYTES_Pos) | I2C_CR2_AUTOEND | (addr << I2C_CR2_SADD_Pos);
|
||||
I2C1->CR2 |= I2C_CR2_START;
|
||||
|
||||
if (st_i2c.blocking) {
|
||||
while ((!(DMA1->ISR & DMA_ISR_TCIF6)) || (I2C1->ISR & I2C_ISR_BUSY)) {
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void i2c_nonblocking_mode() {
|
||||
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
|
||||
while (DMA1_Channel6->CCR & DMA_CCR_EN) {
|
||||
/* do nothing */
|
||||
}
|
||||
DMA1_Channel6->CCR |= DMA_CCR_TCIE;
|
||||
|
||||
st_i2c.blocking = false;
|
||||
}
|
||||
|
||||
void i2c_blocking_mode() {
|
||||
DMA1_Channel6->CCR &= ~DMA_CCR_EN;
|
||||
while (DMA1_Channel6->CCR & DMA_CCR_EN) {
|
||||
/* do nothing */
|
||||
}
|
||||
DMA1_Channel6->CCR &= ~DMA_CCR_TCIE;
|
||||
|
||||
st_i2c.blocking = true;
|
||||
}
|
||||
|
||||
void DMA1_Channel4_5_6_7_IRQHandler() {
|
||||
|
|
@ -486,6 +538,16 @@ void DMA1_Channel4_5_6_7_IRQHandler() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void I2C1_IRQHandler() {
|
||||
int flags = I2C1->ISR;
|
||||
if (flags & (I2C_ISR_ARLO | I2C_ISR_BERR)) {
|
||||
I2C1->ICR = I2C_ISR_ARLO | I2C_ISR_BERR;
|
||||
asm volatile ("bkpt");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define USB_EP0_SIZE 8
|
||||
#define USB_CDC_RX_EP 0x01
|
||||
#define USB_CDC_TX_EP 0x81
|
||||
|
|
@ -864,7 +926,7 @@ int main(void) {
|
|||
"LINE 2 LINE 2 LINE 2",
|
||||
"LINE 3 LINE 3 LINE 3",
|
||||
"LINE 4 LINE 4 LINE 4"};
|
||||
lcd_write(lines);
|
||||
lcd_write_dma(lines);
|
||||
led_init();
|
||||
|
||||
usbd_init(&usb_dev, &usbd_hw, USB_EP0_SIZE, usb_buf, sizeof(usb_buf));
|
||||
|
|
@ -903,7 +965,7 @@ int main(void) {
|
|||
st_led.led[i].b += 3;
|
||||
}
|
||||
for (size_t i=0; i<100000; i++) {
|
||||
lcd_poll();
|
||||
asm volatile ("nop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue