diff --git a/src/main.rs b/src/main.rs index 7ebe48a..f697c6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ use hcl::dma::*; mod systick; mod printer; mod max6675; +mod st7735; use printer::UsartPrinter; @@ -106,13 +107,19 @@ fn run(mut scs: scs::Instance, mut p: hcl::platform::Instance) { let mut printer = UsartPrinter::init(p.usart2); - let spi = &mut p.spi1; - let gpio = &mut p.gpio_a; + let mut spi = p.spi1; + let mut gpio = p.gpio_a; + + let mut st7735 = st7735::St7735::new(st7735::DisplayType::RED_18_BLACKTAB, 0, 1, 4, 8); + + let mut st7735io = st7735.start(spi, gpio); + st7735io.init(); + let (st7735, mut spi, mut gpio) = st7735io.done(); loop { - let res = max6675::read(spi, gpio, 9); + let res = max6675::read(&mut spi, &mut gpio, 9); let msg = match res { Ok(temp) => format!("> {}\r\n", temp).into_bytes(), diff --git a/src/st7735.rs b/src/st7735.rs new file mode 100644 index 0000000..6ed80e1 --- /dev/null +++ b/src/st7735.rs @@ -0,0 +1,396 @@ +use hcl::platform::PeripheralRef; +use hcl::platform::Location; +use hcl::platform::spi; +use hcl::platform::gpio; + +use systick::delay_ms; + +const DEFAULT_WIDTH : u8 = 128; +// for 1.44" display +const DEFAULT_HEIGHT_144 : u8 = 128; +// for 1.8" display +const DEFAULT_HEIGHT_18 : u8 = 160; + +pub enum DisplayType { + BLUE, + RED_18_GREENTAB, + RED_18_REDTAB, + RED_18_BLACKTAB, + RED144_GREENTAB +} + + +// ST7735 commands +enum Command { + NOP, + SWRESET, + RDDID, + RDDST, + + SLPIN, + SLPOUT, + PTLON, + NORON, + + INVOFF, + INVON, + DISPOFF, + DISPON, + CASET(u8, u8, u8, u8), + RASET(u8, u8, u8, u8), + RAMWR, + RAMRD, + + PTLAR, + COLMOD(u8), + MADCTL(u8), + + FRMCTR1(u8, u8, u8), + FRMCTR2(u8, u8, u8), + FRMCTR3(u8, u8, u8, u8, u8, u8), + INVCTR(u8), + DISSET5(u8, u8), + + PWCTR1(u8, u8), + PWCTR2(u8), + PWCTR3(u8, u8), + PWCTR4(u8, u8), + PWCTR5(u8, u8), + PWCTR6(u8, u8), + VMCTR1(u8, u8), + + RDID1, + RDID2, + RDID3, + RDID4, + + GMCTRP1(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8), + GMCTRN1(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8), +} + +fn command_to_byte(cmd : Command) -> u8 { + match cmd { + Command::NOP => 0x00, + Command::SWRESET => 0x01, + Command::RDDID => 0x04, + Command::RDDST => 0x09, + + Command::SLPIN => 0x10, + Command::SLPOUT => 0x11, + Command::PTLON => 0x12, + Command::NORON => 0x13, + + Command::INVOFF => 0x20, + Command::INVON => 0x21, + Command::DISPOFF => 0x28, + Command::DISPON => 0x29, + Command::CASET(_, _, _, _) => 0x2A, + Command::RASET(_, _, _, _) => 0x2B, + Command::RAMWR => 0x2C, + Command::RAMRD => 0x2E, + + Command::PTLAR => 0x30, + Command::COLMOD(_) => 0x3A, + Command::MADCTL(_) => 0x36, + + Command::FRMCTR1(_, _, _) => 0xB1, + Command::FRMCTR2(_, _, _) => 0xB2, + Command::FRMCTR3(_, _, _, _, _, _) => 0xB3, + Command::INVCTR(_) => 0xB4, + Command::DISSET5(_,_) => 0xB6, + + Command::PWCTR1(_, _) => 0xC0, + Command::PWCTR2(_) => 0xC1, + Command::PWCTR3(_, _) => 0xC2, + Command::PWCTR4(_, _) => 0xC3, + Command::PWCTR5(_, _) => 0xC4, + Command::PWCTR6(_, _) => 0xFC, + Command::VMCTR1(_, _) => 0xC5, + + Command::RDID1 => 0xDA, + Command::RDID2 => 0xDB, + Command::RDID3 => 0xDC, + Command::RDID4 => 0xDD, + + Command::GMCTRP1(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,) => 0xE0, + Command::GMCTRN1(_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _,) => 0xE1 + } +} + + +// Initialization commands for 7735B screens +const ST7735_BLUE_INIT : [(Command, u32); 18] = [ + (Command::SWRESET, 50), // 1: Software reset, 50 ms delay + (Command::SLPOUT, 500), // 2: Out of sleep mode, 500ms delay + (Command::COLMOD(0x05), 10), // 3: Set color mode, 16-bit color, 10ms delay + (Command::FRMCTR1(0x00, 0x06, 0x03), 10), // 4: Frame rate control, + // fastest refresh, + // 6 lines front porch, + // 3 lines back porch + // 10ms delay + (Command::MADCTL(0x08), 0), // 5: Memory access ctrl (directions) + // Row addr/col addr, bottom to top refresh + (Command::DISSET5(0x15,0x02), 0), // 6: Display settings #5, + // 1 clk cycle nonoverlap, 2 cycle gate + // Fix on VTL + (Command::INVCTR(0x00), 0), // 7: Display inversion control, + // Line inversion + (Command::PWCTR1(0x02, 0x07), 10), // 8: Power control, + // GVDD = 4.7V + // 1.0uA + // 10 ms delay + (Command::PWCTR2(0x05), 0), // 9: Power control, + // GH = 14.7V, VGL = -7.35V + (Command::PWCTR3(0x01, 0x02), 0), // 10: Power control, + // Opamp current small + // Boost frequency + (Command::VMCTR1(0x3C, 0x38), 10), // 11: Power control + // VCOMH = 4V + // VCOML = -1.1V + // 10 ms delay + (Command::PWCTR6(0x11, 0x15), 0), // 12: Power control + (Command::GMCTRP1(0x09, 0x16, 0x09, 0x20, // 13: Magical unicorn dust + 0x21, 0x1B, 0x13, 0x19, + 0x17, 0x15, 0x1E, 0x2B, + 0x04, 0x05, 0x02, 0x0E), 0), + (Command::GMCTRN1(0x0B, 0x14, 0x08, 0x1E, // 14: Sparkles and rainbows + 0x22, 0x1D, 0x18, 0x1E, + 0x1B, 0x1A, 0x24, 0x2B, + 0x06, 0x06, 0x02, 0x0F), 10), // 10ms delay + (Command::CASET(0x00, 0x02, 0x00, 0x81), 0), // 15: Column addr set + // XSTART = 2 + // XEND = 129 + (Command::RASET(0x00, 0x02, 0x00, 0x81), 0), // 16: Row addr set + // XSTART = 1 + // XEND = 160 + (Command::NORON, 10), // 17: Normal display on, 10ms delay + (Command::DISPON, 500) // 18: Main screen turn on, 500ms delay +]; + + +// Init for 7735R, part 1 (red or green tab) +const ST7735_RED_INIT : [(Command, u32); 15] = [ + (Command::SWRESET, 150), // 1: Software reset, 150ms delay + (Command::SLPOUT, 500), // 2: Out of sleep mode + (Command::FRMCTR1(0x01, 0x2C, 0x2D), 0), // 3: Frame rate ctrl - normal mode + // Rate = fosc/(1x2+40) * (LINE+2C+2D) + (Command::FRMCTR2(0x01, 0x2C, 0x2D), 0), // 4: Frame rate control - idle mode + // Rate = fosc/(1x2+40) * (LINE+2C+2D) + (Command::FRMCTR3(0x01, 0x2C, 0x2D, // 5: Frame rate ctrl - partial mode + 0x01, 0x2C, 0x2D), 0), // Dot inversion mode + // Line inversion mode + (Command::INVCTR(0x07), 0), // 6: Display inversion ctrl + // No inversion + (Command::PWCTR1(0xA2, 0x02), 0), // 7: Power control, -4.6V AUTO mode + (Command::PWCTR2(0xC5), 0), // 8: Power control + // VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD + (Command::PWCTR3(0x0A, 0x00), 0), // 9: Power control: + // Opamp current small + // Boost frequency + (Command::PWCTR4(0x8A, 0x2A),0), // 10: Power control, 2 args, no delay: + // BCLK/2, Opamp current small & Medium low + (Command::PWCTR5(0x8A, 0xEE), 0), // 11: Power control + (Command::VMCTR1(0x0E, 0x4D), 0), // 12: Power control + + (Command::INVOFF, 0), // 13: Don't invert display + (Command::MADCTL(0xC8), 0), // 14: Memory access control (directions), 1 arg: + // row addr/col addr, bottom to top refresh + (Command::COLMOD(0x05), 0) // 15: set color mode, 1 arg, no delay: + // 16-bit color +]; + + +// Init for 7735R, part 2 (green tab only) +const ST7735_RED_INIT_GREEN2 : [(Command, u32); 2] = [ + (Command::CASET(0x00, 0x02, 0x00, 0x7F+0x02), 0), // 1: Column addr set + // XSTART = 0 + // XEND = 127 + (Command::RASET(0x00, 0x01, 0x00, 0x9F+0x01), 0) // 2: Row addr set + // XSTART = 0 + // XEND = 159 +]; + +// Init for 7735R, part 2 (red tab only) +const ST7735_RED_INIT_RED2 : [(Command, u32); 2] = [ + (Command::CASET(0x00, 0x00, 0x00, 0x7F), 0), // 1: Column addr set, 4 args, no delay: + // XSTART = 0 + // XEND = 127 + (Command::RASET(0x00, 0x00, 0x00, 0x9F),0) // 2: Row addr set, 4 args, no delay: + // XSTART = 0 + // XEND = 159 +]; + +// Init for 7735R, part 2 (green 1.44 tab) +const ST7735_RED_INIT_GREEN1442 : [(Command, u32); 2] = [ + (Command::CASET(0x00, 0x00, 0x00, 0x7F), 0), // 1: Column addr set, 4 args, no delay: + // XSTART = 0 + // XEND = 127 + (Command::RASET(0x00, 0x00, 0x00, 0x7F), 0) // 2: Row addr set, 4 args, no delay: + // XSTART = 0 + // XEND = 127 +]; + + // Init for 7735R, part 3 (red or green tab) +const ST7735_RED_INIT3: [(Command, u32); 4] = [ + (Command::GMCTRP1(0x02, 0x1c, 0x07, 0x12, // 1: Magical unicorn dust + 0x37, 0x32, 0x29, 0x2d, + 0x29, 0x25, 0x2B, 0x39, + 0x00, 0x01, 0x03, 0x10), 0), + (Command::GMCTRN1(0x03, 0x1d, 0x07, 0x06, // 2: Sparkles and rainbows + 0x2E, 0x2C, 0x29, 0x2D, + 0x2E, 0x2E, 0x37, 0x3F, + 0x00, 0x00, 0x02, 0x10), 0), + (Command::NORON, 10), // 3: Normal display, 10 ms delay + (Command::DISPON, 100) // 4: Main screen turn on, 100 ms delay +]; + + +pub struct St7735 { + display_type : DisplayType, + column_start : u8, + row_start : u8, + width : u8, + height : u8, + + cs_pin : u32, + rst_pin : u32, + rs_pin : u32, + led_pin : u32 +} + +pub struct St7735IO + where SPIAddr: Location, + GPIOAddr: Location { + st7735 : St7735, + spi : PeripheralRef, + gpio : PeripheralRef, +} + + +impl St7735 { + pub fn new(display_type : DisplayType, cs_pin : u32, rst_pin : u32, rs_pin : u32, led_pin : u32) -> St7735 { + match display_type { + DisplayType::BLUE => St7735 { + display_type : display_type, + cs_pin : cs_pin, + rst_pin : rst_pin, + rs_pin : rs_pin, + led_pin: led_pin, + column_start : 0, + row_start: 0, + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT_18, + }, + DisplayType::RED_18_GREENTAB => St7735 { + display_type : display_type, + cs_pin : cs_pin, + rst_pin : rst_pin, + rs_pin : rs_pin, + led_pin: led_pin, + column_start : 2, + row_start: 1, + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT_18, + }, + DisplayType::RED_18_REDTAB => St7735 { + display_type : display_type, + cs_pin : cs_pin, + rst_pin : rst_pin, + rs_pin : rs_pin, + led_pin: led_pin, + column_start : 0, + row_start: 0, + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT_18, + }, + DisplayType::RED_18_BLACKTAB => St7735 { + display_type : display_type, + cs_pin : cs_pin, + rst_pin : rst_pin, + rs_pin : rs_pin, + led_pin: led_pin, + column_start : 0, + row_start: 0, + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT_18, + }, + DisplayType::RED144_GREENTAB => St7735 { + display_type : display_type, + cs_pin : cs_pin, + rst_pin : rst_pin, + rs_pin : rs_pin, + led_pin: led_pin, + column_start : 2, + row_start: 3, + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT_144, + }, + } + } + + pub fn start(self, spi : PeripheralRef, gpio : PeripheralRef) + -> St7735IO + where SPIAddr: Location, + GPIOAddr: Location { + St7735IO { + st7735: self, + spi : spi, + gpio : gpio + } + } +} + +impl St7735IO + where SPIAddr: Location, + GPIOAddr: Location { + + fn set_rs(&mut self) { + self.gpio.set_bit(self.st7735.rs_pin); + } + + fn reset_rs(&mut self) { + self.gpio.reset_bit(self.st7735.rs_pin); + } + + fn set_rst(&mut self) { + self.gpio.set_bit(self.st7735.rst_pin); + } + + fn reset_rst(&mut self) { + self.gpio.reset_bit(self.st7735.rst_pin); + } + + fn set_cs(&mut self) { + self.gpio.set_bit(self.st7735.cs_pin); + } + + fn reset_cs(&mut self) { + self.gpio.reset_bit(self.st7735.cs_pin); + } + + fn enable_led(&mut self) { + self.gpio.set_bit(self.st7735.led_pin); + } + + fn disable_led(&mut self) { + self.gpio.reset_bit(self.st7735.led_pin); + } + + fn reset(&mut self) { + self.reset_cs(); + self.set_rst(); + delay_ms(500); + self.reset_rst(); + delay_ms(500); + self.set_rst(); + delay_ms(500); + } + + pub fn init(&mut self) { + + } + + pub fn done(self) -> (St7735, PeripheralRef, PeripheralRef) { + (self.st7735, self.spi, self.gpio) + } +}