Class: Denko::Display::ST7302
- Inherits:
-
Object
- Object
- Denko::Display::ST7302
- Includes:
- Behaviors::Lifecycle, SPICommon
- Defined in:
- lib/denko/display/st7302.rb
Constant Summary collapse
- SWRESET =
Commands
0x01- DISPOFF =
0x28- DISPON =
0x29- OSC_EN =
0xC7- BSTEN =
0xD1- SLPIN =
0x10- SLPOUT =
0x11- HPM =
0x38- LPM =
0x39- NVMLOADEN =
0xEB- NVMLOADCTRL =
0xD7- GCTRL =
0xC0- SCTRL1 =
0xC1- SCTRL2 =
0xC2- VCOMCTRL =
0xCB- GATEUPDEQ =
0xB4- DUTYSET =
0xB0- DTFORM =
0x3A- SOCSET =
0xB9- PNLSET =
0xB8- MADCTL =
0x36- CASET =
0x2A- RASET =
0x2B- INVOFF =
0x20- INVON =
0x21- FRCTRL =
0xB2- RAMWR =
0x2C- RAM_COLUMN_START =
Each column in the controller’s RAM is 12 pixels wide. The hardware suppports column addresses 20..39 and for a 122 pixel wide display, the first used column is 25.
25- COLUMNS =
Treat memory rows as columns, and columns as rows. Bytes will fall properly.
250- ROWS =
122- VALID_FRAME_RATES =
{ # High power mode 32 => [0x1, 0x0], 16 => [0x0, 0x0], # Low power mode 8 => [0x0, 0x5], 4 => [0x0, 0x4], 2 => [0x0, 0x3], 1 => [0x0, 0x2], 0.5 => [0x0, 0x1], 0.25 => [0x0, 0x0] }
Constants included from Behaviors::Lifecycle
Behaviors::Lifecycle::CALLBACK_METHODS
Instance Attribute Summary
Attributes included from SPI::Peripheral
#spi_bit_order, #spi_frequency, #spi_mode
Attributes included from Behaviors::State
Attributes included from Behaviors::Component
Attributes included from Behaviors::MultiPin
Instance Method Summary collapse
- #draw_partial(buffer, x_start, x_finish, p_start, p_finish, color = 1) ⇒ Object
- #frame_rate=(fps) ⇒ Object
- #invert_off ⇒ Object
- #invert_on ⇒ Object
-
#pack_lower4(left, right) ⇒ Object
This controller maps memory to pixels in a very unusual way, different to Canvas.
- #pack_upper4(left, right) ⇒ Object
Methods included from SPICommon
#command, #data, #initialize_pins, #transfer_limit
Methods included from PixelCommon
#canvas, #colors, #columns, #draw, #get_partial_buffer, #p_max, #p_min, #refresh, #rows, #x_max, #x_min, #y_max, #y_min
Methods included from SPI::Peripheral
#ensure_byte_array, #initialize_pins, #proxy_pin, #spi_listen, #spi_read, #spi_stop, #spi_transfer, #spi_write, #update
Methods included from Behaviors::Lifecycle
Methods included from Behaviors::Callbacks
#add_callback, #callbacks, #pre_callback_filter, #remove_callback, #update
Methods included from Behaviors::State
Methods included from Behaviors::BusPeripheral
Methods included from Behaviors::Component
Methods included from Behaviors::MultiPin
#convert_pins, #proxy_pin, #proxy_states, #require_pin, #require_pins
Instance Method Details
#draw_partial(buffer, x_start, x_finish, p_start, p_finish, color = 1) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/denko/display/st7302.rb', line 152 def draw_partial(buffer, x_start, x_finish, p_start, p_finish, color=1) # Controller does 2 pixels for each memory line. Ensure start on even. x_start = (x_start / 2.0).floor * 2 # Because of weird RAM layout, always start partials on a framebuffer page divisible by 3. # This corresponds to row divisible by 24, so a RAM column (12 px tall) divisible by 2. # Always write to RAM in pairs of pages. Avoids keeping track of separated nibbles from buffer. # Don't care to optimize this further. page = (p_start / 3.0).floor * 3 # Each RAM column address is really 2 canvas columns. ram_x_start = x_start / 2 ram_x_finish = (x_finish / 2.0).floor while (page <= p_finish) do upper_page = [] lower_page = [] x = x_start while (x <= x_finish) do # Take 6 bytes from the Canvas buffer, 2 columns across, 3 pages (24 rows) down. a1_index = (page * columns) + x a2_index = ((page+1) * columns) + x a3_index = ((page+2) * columns) + x b1_index = (page * columns) + x+1 b2_index = ((page+1) * columns) + x+1 b3_index = ((page+2) * columns) + x+1 a1 = buffer[a1_index] || 0 a2 = buffer[a2_index] || 0 a3 = buffer[a3_index] || 0 b1 = buffer[b1_index] || 0 b2 = buffer[b2_index] || 0 b3 = buffer[b3_index] || 0 # Transform them to match the RAM format, and add to their respective temp pages. upper_page += [pack_lower4(a1, b1), pack_upper4(a1, b1), pack_lower4(a2, b2)] lower_page += [pack_upper4(a2, b2), pack_lower4(a3, b3), pack_upper4(a3, b3)] x += 2 end # Transform from FB page index (8 px per page) to RAM column index (12 px per column). ram_page = ((page * 8) / 12) + RAM_COLUMN_START # Write two temp pages into 2 controller RAM columns. command [CASET]; data [ram_page, ram_page+1] command [RASET]; data [ram_x_start, ram_x_finish] command [RAMWR] upper_page.each_slice(transfer_limit) { |slice| data(slice) } lower_page.each_slice(transfer_limit) { |slice| data(slice) } # Advance 3 framebuffer pages since taking 24 rows each loop. page += 3 end end |
#frame_rate=(fps) ⇒ Object
97 98 99 100 101 102 103 |
# File 'lib/denko/display/st7302.rb', line 97 def frame_rate=(fps) raise ArgumentError, "Invalid frame rate: #{fps} given" unless VALID_FRAME_RATES.keys.include? fps power_mode = (fps > 8) ? HPM : LPM command [power_mode] command [FRCTRL] data VALID_FRAME_RATES[fps] end |
#invert_off ⇒ Object
81 82 83 |
# File 'lib/denko/display/st7302.rb', line 81 def invert_off command [INVOFF] end |
#invert_on ⇒ Object
77 78 79 |
# File 'lib/denko/display/st7302.rb', line 77 def invert_on command [INVON] end |
#pack_lower4(left, right) ⇒ Object
This controller maps memory to pixels in a very unusual way, different to Canvas. Each “chunk” it accepts is 3 bytes (A through C below), representing: 2 pixels wide (2 columns in Canvas FB, or 1 “line” on the controller), by 12 pixels tall (1.5 pages in Canvas FB or 1 “column” on the controller):
A7 A6 - A5 A4 | A3 A2 | In framebuffer space this maps to: A1 A0 |- 2 complete bytes, sequential colummns, on same Canvas page, B7 B6 | but they have to be interleaved in controller RAM B5 B4 | B3 B2 | B1 B0 - C7 C6 - C5 C4 | C3 C2 |- Same as above, but 2 low nibbles from 2 sequential bytes C1 C0 -
For odd numbered “chunks”, this is flipped. The corresponding high nibbles are first, then 2 whole bytes. Note that bit order is reversed compared to Canvas…
Also note we are mapping Canvas framebuffer pages to what the controller calls “columns”, and mapping framebuffer columns to what the controller calls “rows”, essentially rotating it by 90 degrees. This makes it easier to transform a Canvas framebuffer into device RAM.
Finally, use these 2 packing methods to take either the lower or upper nibbles from a pair of bytes, inteleave and reverse them to fit the format above.
134 135 136 137 138 139 140 141 |
# File 'lib/denko/display/st7302.rb', line 134 def pack_lower4(left, right) result = 0 (0..3).each do |index| result |= ((left >> index) & 0b1) << (7 - (index*2)) result |= ((right >> index) & 0b1) << (7 - (index*2 + 1)) end result end |
#pack_upper4(left, right) ⇒ Object
143 144 145 146 147 148 149 150 |
# File 'lib/denko/display/st7302.rb', line 143 def pack_upper4(left, right) result = 0 (4..7).each do |index| result |= ((left >> index) & 0b1) << (7 - ((index-4)*2)) result |= ((right >> index) & 0b1) << (7 - ((index-4)*2 + 1)) end result end |