Try to implement a display driver (but failed). hardware problem? new processor incoming anyways

This commit is contained in:
Jan-Henrik 2019-09-02 13:41:24 +02:00
parent ae6dee2434
commit 53a833fb33
5 changed files with 298 additions and 39 deletions

176
midi2cv/drivers/display.cc Normal file
View file

@ -0,0 +1,176 @@
#include "display.h"
#include "gpio.h"
#include <stm32f10x_conf.h>
// SH1106 command definitions
#define SH1106_CMD_SETMUX (uint8_t)0xA8 // Set multiplex ratio (N, number of lines active on display)
#define SH1106_CMD_SETOFFS (uint8_t)0xD3 // Set display offset
#define SH1106_CMD_STARTLINE (uint8_t)0x40 // Set display start line
#define SH1106_CMD_SEG_NORM (uint8_t)0xA0 // Column 0 is mapped to SEG0 (X coordinate normal)
#define SH1106_CMD_SEG_INV (uint8_t)0xA1 // Column 127 is mapped to SEG0 (X coordinate inverted)
#define SH1106_CMD_COM_NORM (uint8_t)0xC0 // Scan from COM0 to COM[N-1] (N - mux ratio, Y coordinate normal)
#define SH1106_CMD_COM_INV (uint8_t)0xC8 // Scan from COM[N-1] to COM0 (N - mux ratio, Y coordinate inverted)
#define SH1106_CMD_COM_HW (uint8_t)0xDA // Set COM pins hardware configuration
#define SH1106_CMD_CONTRAST (uint8_t)0x81 // Contrast control
#define SH1106_CMD_EDON (uint8_t)0xA5 // Entire display ON enabled (all pixels on, RAM content ignored)
#define SH1106_CMD_EDOFF (uint8_t)0xA4 // Entire display ON disabled (output follows RAM content)
#define SH1106_CMD_INV_OFF (uint8_t)0xA6 // Entire display inversion OFF (normal display)
#define SH1106_CMD_INV_ON (uint8_t)0xA7 // Entire display inversion ON (all pixels inverted)
#define SH1106_CMD_CLOCKDIV (uint8_t)0xD5 // Set display clock divide ratio/oscillator frequency
#define SH1106_CMD_DISP_ON (uint8_t)0xAF // Display ON
#define SH1106_CMD_DISP_OFF (uint8_t)0xAE // Display OFF (sleep mode)
#define SH1106_CMD_COL_LOW (uint8_t)0x00 // Set Lower Column Address
#define SH1106_CMD_COL_HIGH (uint8_t)0x10 // Set Higher Column Address
#define SH1106_CMD_PAGE_ADDR (uint8_t)0xB0 // Set Page Address
#define SH1106_CMD_CHARGE (uint8_t)0x22 // Dis-charge / Pre-charge Period
#define SH1106_CMD_SCRL_HR (uint8_t)0x26 // Setup continuous horizontal scroll right
#define SH1106_CMD_SCRL_HL (uint8_t)0x27 // Setup continuous horizontal scroll left
#define SH1106_CMD_SCRL_VHR (uint8_t)0x29 // Setup continuous vertical and horizontal scroll right
#define SH1106_CMD_SCRL_VHL (uint8_t)0x2A // Setup continuous vertical and horizontal scroll left
#define SH1106_CMD_SCRL_STOP (uint8_t)0x2E // Deactivate scroll
#define SH1106_CMD_SCRL_ACT (uint8_t)0x2F // Activate scroll
void Display::Init()
{
gpio.Write(GPIO_PIN(SS_OLED), Bit_SET); // deactivate OLED spi
gpio.Write(GPIO_PIN(RST_OLED), Bit_SET);
gpio.Write(GPIO_PIN(RST_OLED), Bit_RESET);
gpio.Write(GPIO_PIN(RST_OLED), Bit_SET);
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
SPI_InitTypeDef spi_init;
spi_init.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
spi_init.SPI_Mode = SPI_Mode_Master;
spi_init.SPI_DataSize = SPI_DataSize_8b;
spi_init.SPI_CPOL = SPI_CPOL_Low;
spi_init.SPI_CPHA = SPI_CPHA_1Edge;
spi_init.SPI_NSS = SPI_NSS_Soft;
spi_init.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
spi_init.SPI_FirstBit = SPI_FirstBit_LSB;
spi_init.SPI_CRCPolynomial = 10;
SPI_Init(SPI2, &spi_init);
SPI_CalculateCRC(SPI2, DISABLE);
SPI_Cmd(SPI2, ENABLE);
#define SH1106_cmd_double(x, y) \
WriteCommand(x); \
WriteCommand(y);
#define SH1106_cmd(x) WriteCommand(x);
// Set multiplex ratio (visible lines)
SH1106_cmd_double(SH1106_CMD_SETMUX, 0x3F); // 64MUX
// Set display offset (offset of first line from the top of display)
SH1106_cmd_double(SH1106_CMD_SETOFFS, 0x00); // Offset: 0
// Set display start line (first line displayed)
SH1106_cmd(SH1106_CMD_STARTLINE | 0x00); // Start line: 0
// Set segment re-map (X coordinate)
SH1106_cmd(SH1106_CMD_SEG_NORM);
// Set COM output scan direction (Y coordinate)
SH1106_cmd(SH1106_CMD_COM_NORM);
// Set COM pins hardware configuration
// bit[4]: reset - sequential COM pin configuration
// set - alternative COM pin configuration (reset value)
// bit[5]: reset - disable COM left/right remap (reset value)
// set - enable COM left/right remap
SH1106_cmd_double(SH1106_CMD_COM_HW, 0x12);
uint8_t dis_charge = 0x00;
uint8_t pre_charge = 0x00;
SH1106_cmd_double(SH1106_CMD_CHARGE, dis_charge | (pre_charge << 4));
// Set contrast control
SH1106_cmd_double(SH1106_CMD_CONTRAST, 0x0F); // Contrast: middle level
SH1106_cmd(0x30);
// Disable entire display ON
SH1106_cmd(SH1106_CMD_EDOFF); // Display follows RAM content
// Disable display inversion
SH1106_cmd(SH1106_CMD_INV_OFF); // Normal display mode
// Set clock divide ratio and oscillator frequency
// bits[3:0] defines the divide ratio of the display clocks (bits[3:0] + 1)
// bits[7:4] set the oscillator frequency (Fosc), frequency increases with the value of these bits
// 0xF0 value gives maximum frequency (maximum Fosc without divider)
// 0x0F value gives minimum frequency (minimum Fosc divided by 16)
// The higher display frequency decreases image flickering but increases current consumption and vice versa
SH1106_cmd_double(SH1106_CMD_CLOCKDIV, 0xF0);
// Display ON
SH1106_cmd(SH1106_CMD_DISP_ON); // Display enabled
SH1106_cmd(SH1106_CMD_EDON);
Clear();
Update();
}
void Display::WriteCommand(uint8_t byte)
{
gpio.Write(GPIO_PIN(SDC_OLED), Bit_RESET); // command mode
gpio.Write(GPIO_PIN(SS_OLED), Bit_RESET); // activate OLED spi
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET)
;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
;
SPI_I2S_SendData(SPI2, byte); // transmit via spi
gpio.Write(GPIO_PIN(SS_OLED), Bit_SET); // disable oled spi
}
void Display::WriteData(uint8_t* buffer, uint8_t size)
{
gpio.Write(GPIO_PIN(SDC_OLED), Bit_SET); // data mode
gpio.Write(GPIO_PIN(SS_OLED), Bit_RESET); // activate OLED spi
for (int i = 0; i < size; i++) {
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET)
;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
;
SPI_I2S_SendData(SPI2, buffer[i]); // transmit via spi
for (int i = 0; i < 100; i++)
;
}
gpio.Write(GPIO_PIN(SS_OLED), Bit_SET); // disable oled spi
}
void Display::Clear()
{
uint32_t i = 0;
for (i = 0; i < sizeof(buffer); i++)
buffer[i] = 0x00;
}
void Display::Update()
{
for (uint32_t i = 0; i < 8; i++) {
WriteCommand(0xb0 + i);
WriteCommand(0x00);
WriteCommand(0x10);
WriteData(&buffer[128 * i], 128);
}
}
void Display::WritePixel(uint8_t x, uint8_t y, bool color)
{
if (x > DISPLAY_WIDTH || y > DISPLAY_HEIGHT)
return;
if (color) {
buffer[x + (y / 8) * DISPLAY_WIDTH] |= 1 << (y % 8);
} else {
buffer[x + (y / 8) * DISPLAY_WIDTH] &= ~(1 << (y % 8));
}
}

29
midi2cv/drivers/display.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef MIDI2CV_DRIVERS_DISPLAY_H
#define MIDI2CV_DRIVERS_DISPLAY_H
#include <stm32f10x_conf.h>
#include "stmlib/stmlib.h"
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
class Display {
public:
Display() { }
~Display() {}
void Init();
void WritePixel(uint8_t x, uint8_t y, bool color);
void Clear();
void Update();
private:
DISALLOW_COPY_AND_ASSIGN(Display);
void WriteCommand(uint8_t byte);
void WriteData(uint8_t* data, uint8_t length);
uint8_t buffer[DISPLAY_WIDTH*DISPLAY_HEIGHT / 8];
};
#endif

View file

@ -2,10 +2,11 @@
#include <stm32f10x_conf.h> #include <stm32f10x_conf.h>
void GPIO::Init() { void GPIO::Init() {
GPIO_InitTypeDef gpio_init; GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = PIN_SS_DAC0 | PIN_SS_DAC1 | PIN_RST_USB | PIN_SS_USB | PIN_SS_OLED | PIN_SDC_OLED; gpio_init.GPIO_Pin = PIN_RST_OLED | PIN_SS_DAC0 | PIN_SS_DAC1 | PIN_RST_USB | PIN_SS_USB | PIN_SS_OLED | PIN_SDC_OLED;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz; gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP; gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &gpio_init); GPIO_Init(GPIOB, &gpio_init);
@ -14,6 +15,11 @@ void GPIO::Init() {
gpio_init.GPIO_Speed = GPIO_Speed_50MHz; gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP; gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &gpio_init); GPIO_Init(GPIOA, &gpio_init);
Write(GPIO_PIN(SS_DAC0), Bit_SET);
Write(GPIO_PIN(SS_DAC1), Bit_SET);
Write(GPIO_PIN(SS_USB), Bit_SET);
Write(GPIO_PIN(SS_OLED), Bit_SET);
} }
void GPIO::Write(GPIO_TypeDef* port, uint16_t pin, bool state) { void GPIO::Write(GPIO_TypeDef* port, uint16_t pin, bool state) {

View file

@ -5,6 +5,8 @@
#include "stmlib/stmlib.h" #include "stmlib/stmlib.h"
#include <stm32f10x_conf.h> #include <stm32f10x_conf.h>
#define PORT_RST_OLED GPIOB
#define PIN_RST_OLED GPIO_Pin_0
#define PORT_SS_DAC0 GPIOB #define PORT_SS_DAC0 GPIOB
#define PIN_SS_DAC0 GPIO_Pin_6 #define PIN_SS_DAC0 GPIO_Pin_6
#define PORT_SS_DAC1 GPIOB #define PORT_SS_DAC1 GPIOB
@ -44,4 +46,7 @@ class GPIO {
DISALLOW_COPY_AND_ASSIGN(GPIO); DISALLOW_COPY_AND_ASSIGN(GPIO);
}; };
extern GPIO gpio;
#endif #endif

View file

@ -1,54 +1,97 @@
#include <stm32f10x_conf.h> #include <stm32f10x_conf.h>
#include "drivers/display.h"
#include "drivers/gpio.h" #include "drivers/gpio.h"
using namespace stmlib; using namespace stmlib;
GPIO gpio; GPIO gpio;
Display display;
// Default interrupt handlers. // Default interrupt handlers.
extern "C" { extern "C" {
void NMI_Handler() { } void NMI_Handler() {}
void HardFault_Handler() { void HardFault_Handler()
while (1); {
} while (1)
void MemManage_Handler() { while (1); } ;
void BusFault_Handler() { while (1); }
void UsageFault_Handler() { while (1); }
void SVC_Handler() { }
void DebugMon_Handler() { }
void PendSV_Handler() { }
// called every 1ms
void SysTick_Handler() {
}
} }
void MemManage_Handler()
{
while (1)
void Init(void) { ;
SystemInit();
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x1000);
RCC_APB2PeriphClockCmd(
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |
RCC_APB2Periph_TIM1 | RCC_APB2Periph_USART1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
gpio.Init();
} }
void BusFault_Handler()
{
while (1)
;
}
void UsageFault_Handler()
{
while (1)
;
}
void SVC_Handler() {}
void DebugMon_Handler() {}
void PendSV_Handler() {}
int main(void) { // called every 1ms
Init(); void SysTick_Handler()
while (1) { {
// hi
gpio.Write(GPIO_PIN(GATE_OUT_1), 1);
gpio.Write(GPIO_PIN(GATE_OUT_2), 0);
gpio.Write(GPIO_PIN(GATE_OUT_3), 1);
gpio.Write(GPIO_PIN(GATE_OUT_4), 0);
} }
} }
void Init(void)
{
SystemInit();
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x1000);
RCC_APB2PeriphClockCmd(
RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_TIM1 | RCC_APB2Periph_USART1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
TIM_TimeBaseInitTypeDef timer_init;
timer_init.TIM_Period = F_CPU / (48000 * 4) - 1;
timer_init.TIM_Prescaler = 0;
timer_init.TIM_ClockDivision = TIM_CKD_DIV1;
timer_init.TIM_CounterMode = TIM_CounterMode_Up;
timer_init.TIM_RepetitionCounter = 0;
TIM_InternalClockConfig(TIM1);
TIM_TimeBaseInit(TIM1, &timer_init);
TIM_Cmd(TIM1, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 2.2 priority split.
// DAC interrupt is given highest priority
NVIC_InitTypeDef timer_interrupt;
timer_interrupt.NVIC_IRQChannel = TIM1_UP_IRQn;
timer_interrupt.NVIC_IRQChannelPreemptionPriority = 0;
timer_interrupt.NVIC_IRQChannelSubPriority = 0;
timer_interrupt.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&timer_interrupt);
SysTick_Config(F_CPU / 8000);
gpio.Init();
// asm("bkpt #0");
display.Init();
}
int main(void)
{
Init();
while (1) {
for (int x = 0; x < DISPLAY_WIDTH; x++)
for (int y = 0; y < DISPLAY_HEIGHT; y++) {
display.WritePixel(x, y, 0xff);
display.WritePixel(DISPLAY_WIDTH - x, DISPLAY_WIDTH - y, 0xff);
}
display.Update();
// hi
gpio.Write(GPIO_PIN(GATE_OUT_1), 0);
gpio.Write(GPIO_PIN(GATE_OUT_2), 0);
gpio.Write(GPIO_PIN(GATE_OUT_3), 0);
gpio.Write(GPIO_PIN(GATE_OUT_4), 0);
gpio.Write(GPIO_PIN(GATE_OUT_5), 0);
gpio.Write(GPIO_PIN(GATE_OUT_6), 0);
}
}