mirror of
https://github.com/jhbruhn/eurorack.git
synced 2025-03-15 02:55:49 +00:00
Try to implement a display driver (but failed). hardware problem? new processor incoming anyways
This commit is contained in:
parent
ae6dee2434
commit
53a833fb33
5 changed files with 298 additions and 39 deletions
176
midi2cv/drivers/display.cc
Normal file
176
midi2cv/drivers/display.cc
Normal 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
29
midi2cv/drivers/display.h
Normal 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
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
#include <stm32f10x_conf.h>
|
||||
|
||||
|
||||
void 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_Mode = GPIO_Mode_Out_PP;
|
||||
GPIO_Init(GPIOB, &gpio_init);
|
||||
|
@ -14,6 +15,11 @@ void GPIO::Init() {
|
|||
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
|
||||
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
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) {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "stmlib/stmlib.h"
|
||||
#include <stm32f10x_conf.h>
|
||||
|
||||
#define PORT_RST_OLED GPIOB
|
||||
#define PIN_RST_OLED GPIO_Pin_0
|
||||
#define PORT_SS_DAC0 GPIOB
|
||||
#define PIN_SS_DAC0 GPIO_Pin_6
|
||||
#define PORT_SS_DAC1 GPIOB
|
||||
|
@ -44,4 +46,7 @@ class GPIO {
|
|||
DISALLOW_COPY_AND_ASSIGN(GPIO);
|
||||
};
|
||||
|
||||
extern GPIO gpio;
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,54 +1,97 @@
|
|||
#include <stm32f10x_conf.h>
|
||||
|
||||
#include "drivers/display.h"
|
||||
#include "drivers/gpio.h"
|
||||
|
||||
using namespace stmlib;
|
||||
|
||||
|
||||
|
||||
GPIO gpio;
|
||||
|
||||
Display display;
|
||||
|
||||
// Default interrupt handlers.
|
||||
extern "C" {
|
||||
void NMI_Handler() {}
|
||||
void HardFault_Handler() {
|
||||
while (1);
|
||||
void HardFault_Handler()
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void MemManage_Handler()
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void BusFault_Handler()
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void UsageFault_Handler()
|
||||
{
|
||||
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 SysTick_Handler()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Init(void) {
|
||||
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_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) {
|
||||
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), 1);
|
||||
gpio.Write(GPIO_PIN(GATE_OUT_1), 0);
|
||||
gpio.Write(GPIO_PIN(GATE_OUT_2), 0);
|
||||
gpio.Write(GPIO_PIN(GATE_OUT_3), 1);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue