33//! See amazing things
44
55use defmt:: * ;
6+
67use embassy_futures:: yield_now;
78use embassy_rp:: {
89 Peri , bind_interrupts,
910 gpio:: Output ,
1011 peripherals:: {
1112 DMA_CH1 , PIN_19 , PIN_20 , PIN_21 , PIN_22 , PIN_23 , PIN_24 , PIN_25 , PIN_26 , PIN_27 , PIO1 ,
1213 } ,
13- pio:: InterruptHandler ,
14- pwm:: Pwm ,
14+ pio:: { Config , InterruptHandler , Pio , StateMachine , program :: pio_asm } ,
15+ pwm:: { Pwm , SetDutyCycle } ,
1516} ;
16- use embassy_time:: { Duration , Instant } ;
17+ use embassy_time:: { Duration , Instant , Timer } ;
18+
19+ use crate :: usb:: usb_suspended;
1720
1821type ScrPio = Peri < ' static , PIO1 > ;
22+ type ScrPioSm = StateMachine < ' static , PIO1 , 0 > ;
1923type ScrDma = Peri < ' static , DMA_CH1 > ;
2024type ScrDataPins = (
2125 Peri < ' static , PIN_19 > ,
@@ -38,23 +42,181 @@ bind_interrupts!(struct Irqs {
3842 PIO1_IRQ_0 => InterruptHandler <PIO1 >;
3943} ) ;
4044
45+ struct St7789_8080 {
46+ sm : ScrPioSm ,
47+ dma : ScrDma ,
48+ cs : ScrCsPin ,
49+ dc : ScrDcPin ,
50+ bl : ScrBlPin ,
51+ _rst : ScrRstPin ,
52+ }
53+ impl St7789_8080 {
54+ pub fn new (
55+ pio : ScrPio ,
56+ dma : ScrDma ,
57+ data : ScrDataPins ,
58+ clk : ScrClkPin ,
59+ mut cs : ScrCsPin ,
60+ mut dc : ScrDcPin ,
61+ mut bl : ScrBlPin ,
62+ mut rst : ScrRstPin ,
63+ ) -> Self {
64+ bl. set_duty_cycle_percent ( 0 ) . unwrap ( ) ;
65+ dc. set_low ( ) ;
66+ cs. set_high ( ) ;
67+ rst. set_high ( ) ;
68+
69+ let Pio {
70+ mut common,
71+ mut sm0,
72+ ..
73+ } = Pio :: new ( pio, Irqs ) ;
74+
75+ let program = pio_asm ! (
76+ // ".pio_version 1"
77+ // ".program st7789_8080"
78+ ".side_set 1"
79+ ".wrap_target"
80+ "out pins, 8 side 0"
81+ "nop side 1"
82+ ".wrap"
83+ ) ;
84+
85+ let mut cfg = Config :: default ( ) ;
86+ let clk = common. make_pio_pin ( clk) ;
87+ let datas = [
88+ & common. make_pio_pin ( data. 0 ) ,
89+ & common. make_pio_pin ( data. 1 ) ,
90+ & common. make_pio_pin ( data. 2 ) ,
91+ & common. make_pio_pin ( data. 3 ) ,
92+ & common. make_pio_pin ( data. 4 ) ,
93+ & common. make_pio_pin ( data. 5 ) ,
94+ & common. make_pio_pin ( data. 6 ) ,
95+ & common. make_pio_pin ( data. 7 ) ,
96+ ] ;
97+ cfg. set_out_pins ( & datas) ;
98+ cfg. fifo_join = embassy_rp:: pio:: FifoJoin :: TxOnly ;
99+ cfg. shift_out . threshold = 16 ;
100+ cfg. shift_out . direction = embassy_rp:: pio:: ShiftDirection :: Left ;
101+ cfg. shift_out . auto_fill = true ;
102+ cfg. clock_divider = 4u8 . into ( ) ;
103+ cfg. use_program ( & common. load_program ( & program. program ) , & [ & clk] ) ;
104+
105+ sm0. set_config ( & cfg) ;
106+ sm0. set_pin_dirs ( embassy_rp:: pio:: Direction :: Out , & [ & clk] ) ;
107+ sm0. set_pin_dirs ( embassy_rp:: pio:: Direction :: Out , & datas) ;
108+
109+ sm0. set_enable ( true ) ;
110+
111+ Self {
112+ sm : sm0,
113+ dma,
114+ cs,
115+ dc,
116+ bl,
117+ _rst : rst,
118+ }
119+ }
120+
121+ fn set_backlight ( & mut self , percent : u8 ) {
122+ self . bl . set_duty_cycle_percent ( percent) . unwrap ( ) ;
123+ }
124+
125+ async fn set_dc_cs ( & mut self , dc : bool , cs : bool ) {
126+ Timer :: after_micros ( 1 ) . await ;
127+
128+ if dc {
129+ self . dc . set_high ( ) ;
130+ } else {
131+ self . dc . set_low ( ) ;
132+ }
133+ if cs {
134+ self . cs . set_high ( ) ;
135+ } else {
136+ self . cs . set_low ( ) ;
137+ }
138+
139+ Timer :: after_micros ( 1 ) . await ;
140+ }
141+
142+ async fn write ( & mut self , word : u16 ) {
143+ self . sm . tx ( ) . wait_push ( ( word as u32 ) << 16 ) . await ;
144+ }
145+
146+ async fn wait_idle ( & mut self ) {
147+ while !self . sm . tx ( ) . stalled ( ) {
148+ yield_now ( ) . await ;
149+ }
150+ }
151+
152+ async fn write_cmd ( & mut self , cmd : & [ u16 ] ) {
153+ self . wait_idle ( ) . await ;
154+ self . set_dc_cs ( false , false ) . await ;
155+
156+ self . write ( cmd[ 0 ] ) . await ;
157+ if cmd. len ( ) >= 2 {
158+ self . wait_idle ( ) . await ;
159+ self . set_dc_cs ( true , false ) . await ;
160+ for c in & cmd[ 1 ..] {
161+ self . write ( * c) . await ;
162+ }
163+ }
164+
165+ self . wait_idle ( ) . await ;
166+ self . set_dc_cs ( true , true ) . await ;
167+ }
168+
169+ pub async fn init ( & mut self , w : u16 , h : u16 ) {
170+ // init sequence
171+ // 16bit startup sequence
172+ self . write_cmd ( & [ 0x0001 ] ) . await ; // Software reset
173+ self . write_cmd ( & [ 0x0011 ] ) . await ; // Exit sleep mode
174+ self . write_cmd ( & [ 0x003A , 0x5500 ] ) . await ; // Set color mode to 16 bit
175+ self . write_cmd ( & [ 0x0036 , 0x0000 ] ) . await ; // Set MADCTL: bottom to top, left to right, refresh is bottom to top // 0b111101_10
176+ self . write_cmd ( & [ 0x002A , 0x0000 , h] ) . await ; // CASET: column addresses
177+ self . write_cmd ( & [ 0x002B , 0x0000 , w] ) . await ; // RASET: row addresses
178+ self . write_cmd ( & [ 0x0021 ] ) . await ; // Inversion on
179+ self . write_cmd ( & [ 0x0013 ] ) . await ; // Normal display on
180+ self . write_cmd ( & [ 0x0029 ] ) . await ; // Main screen turn on
181+ }
182+
183+ async fn start_pixels ( & mut self ) {
184+ self . write_cmd ( & [ 0x002C ] ) . await ;
185+ self . set_dc_cs ( true , false ) . await ;
186+ }
187+
188+ pub async fn push_framebuffer ( & mut self , fb : & ' static [ u16 ; SCR_W * SCR_H ] ) {
189+ self . start_pixels ( ) . await ;
190+ self . sm . tx ( ) . dma_push ( self . dma . reborrow ( ) , fb, false ) . await ;
191+ }
192+ }
193+
41194const POLL_TIME : Duration = Duration :: from_millis ( 100 ) ;
195+ pub const SCR_W : usize = 320 ;
196+ pub const SCR_H : usize = 240 ;
197+ static mut FB : [ u16 ; SCR_W * SCR_H ] = [ 0xFFFF ; SCR_W * SCR_H ] ;
42198
43199struct ScreenMod {
200+ scr : St7789_8080 ,
44201 poll_time : Instant ,
45202}
46203impl ScreenMod {
47- fn new (
204+ async fn new (
48205 pio : ScrPio ,
49206 dma : ScrDma ,
50- data_pins : ScrDataPins ,
51- clk_pin : ScrClkPin ,
52- cs_pin : ScrCsPin ,
53- dc_pin : ScrDcPin ,
54- bl_pin : ScrBlPin ,
55- rst_pin : ScrRstPin ,
207+ data : ScrDataPins ,
208+ clk : ScrClkPin ,
209+ cs : ScrCsPin ,
210+ dc : ScrDcPin ,
211+ bl : ScrBlPin ,
212+ rst : ScrRstPin ,
56213 ) -> Self {
214+ let mut scr = St7789_8080 :: new ( pio, dma, data, clk, cs, dc, bl, rst) ;
215+
216+ scr. init ( SCR_W as u16 , SCR_H as u16 ) . await ;
217+
57218 Self {
219+ scr,
58220 poll_time : unwrap ! ( Instant :: now( ) . checked_add( POLL_TIME ) ) ,
59221 }
60222 }
@@ -68,6 +230,15 @@ impl ScreenMod {
68230 continue ;
69231 }
70232
233+ if !usb_suspended ( ) {
234+ self . scr
235+ . push_framebuffer ( unsafe { & mut * core:: ptr:: addr_of_mut!( FB ) } )
236+ . await ;
237+ self . scr . set_backlight ( 100 ) ;
238+ } else {
239+ self . scr . set_backlight ( 0 ) ;
240+ }
241+
71242 self . poll_time = unwrap ! ( now. checked_add( POLL_TIME ) ) ;
72243 }
73244 }
@@ -77,16 +248,15 @@ impl ScreenMod {
77248pub async fn screen_task (
78249 pio : ScrPio ,
79250 dma : ScrDma ,
80- data_pins : ScrDataPins ,
81- clk_pin : ScrClkPin ,
82- cs_pin : ScrCsPin ,
83- dc_pin : ScrDcPin ,
84- bl_pin : ScrBlPin ,
85- rst_pin : ScrRstPin ,
251+ data : ScrDataPins ,
252+ clk : ScrClkPin ,
253+ cs : ScrCsPin ,
254+ dc : ScrDcPin ,
255+ bl : ScrBlPin ,
256+ rst : ScrRstPin ,
86257) -> ! {
87- ScreenMod :: new (
88- pio, dma, data_pins, clk_pin, cs_pin, dc_pin, bl_pin, rst_pin,
89- )
90- . task ( )
91- . await ;
258+ ScreenMod :: new ( pio, dma, data, clk, cs, dc, bl, rst)
259+ . await
260+ . task ( )
261+ . await ;
92262}
0 commit comments