Software APIs
ssd1131_screen.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/lib/peripherals/ssd1131_screen.h"
6 
7 #include "sw/device/examples/teacup_demos/data/bitmaps.h"
8 #include "sw/device/lib/base/status.h"
12 
13 status_t screen_tx_cmd_or_data(const screen_t *screen, uint8_t data,
14  screen_op_type_t op_type) {
15  dif_spi_host_segment_t segment = {
17  .opcode = {.width = kDifSpiHostWidthStandard, .opcode = data}};
19  TRY(dif_gpio_write(screen->gpio, screen->data_command_gpio, (bool)op_type));
20  TRY(dif_spi_host_transaction(screen->spi_host, /*cs_id=*/0, &segment,
21  /*length=*/1));
23  return OK_STATUS();
24 }
25 
26 status_t screen_toggle_power(const screen_t *screen, bool on) {
27  if (on) {
28  TRY(screen_tx_cmd_or_data(screen, kScreenSetDisplayOn,
29  kScreenOpTypeCommand));
30  } else {
31  TRY(screen_tx_cmd_or_data(screen, kScreenSetDisplayOff,
32  kScreenOpTypeCommand));
33  }
34  return OK_STATUS();
35 }
36 
37 status_t screen_toggle_pixel_mode(const screen_t *screen,
38  screen_pixel_mode_t mode) {
39  TRY(screen_tx_cmd_or_data(screen, (uint8_t)mode, kScreenOpTypeCommand));
40  return OK_STATUS();
41 }
42 
43 status_t screen_set_column_address_range(const screen_t *screen,
44  uint8_t start_address,
45  uint8_t end_address) {
46  if (start_address >= kScreenMaxCols || end_address >= kScreenMaxCols) {
47  return INVALID_ARGUMENT();
48  }
49 
50  TRY(screen_tx_cmd_or_data(screen, kScreenSetColumnAddress,
51  kScreenOpTypeCommand));
52  TRY(screen_tx_cmd_or_data(screen, start_address, kScreenOpTypeCommand));
53  TRY(screen_tx_cmd_or_data(screen, end_address, kScreenOpTypeCommand));
54 
55  return OK_STATUS();
56 }
57 
58 status_t screen_set_row_address_range(const screen_t *screen,
59  uint8_t start_address,
60  uint8_t end_address) {
61  if (start_address >= kScreenMaxRows || end_address >= kScreenMaxRows) {
62  return INVALID_ARGUMENT();
63  }
64 
65  TRY(screen_tx_cmd_or_data(screen, kScreenSetRowAddress,
66  kScreenOpTypeCommand));
67  TRY(screen_tx_cmd_or_data(screen, start_address, kScreenOpTypeCommand));
68  TRY(screen_tx_cmd_or_data(screen, end_address, kScreenOpTypeCommand));
69 
70  return OK_STATUS();
71 }
72 
73 status_t screen_configure_color_format(const screen_t *screen,
74  screen_color_format_t format) {
75  // Set specified color format, in addition to enabling COM split odd/even.
76  uint8_t remap_and_color_format_value = (uint8_t)(format << 6 | 0x20);
77  TRY(screen_tx_cmd_or_data(screen, kScreenSetRemapAndColorFormat,
78  kScreenOpTypeCommand));
79  TRY(screen_tx_cmd_or_data(screen, remap_and_color_format_value,
80  kScreenOpTypeCommand));
81 
82  return OK_STATUS();
83 }
84 
85 status_t screen_draw_bitmap(const screen_t *screen,
86  const screen_bitmap_t *bitmap) {
87  if (bitmap->num_rows > kScreenMaxRows || bitmap->num_cols > kScreenMaxCols) {
88  return INVALID_ARGUMENT();
89  }
90 
91  uint8_t col_start_address = (uint8_t)(kScreenMaxCols - bitmap->num_cols) / 2;
92  uint8_t col_end_address = col_start_address + (uint8_t)bitmap->num_cols - 1;
93  uint8_t row_start_address = (uint8_t)(kScreenMaxRows - bitmap->num_rows) / 2;
94  uint8_t row_end_address = row_start_address + (uint8_t)bitmap->num_rows - 1;
95 
96  for (size_t r = 0; r < kScreenMaxRows; ++r) {
97  for (size_t c = 0; c < kScreenMaxCols; ++c) {
98  uint16_t curr_value = bitmap->fill_color;
99  if (c >= col_start_address && c <= col_end_address &&
100  r >= row_start_address && r <= row_end_address) {
101  size_t adjusted_r = r - row_start_address;
102  size_t adjusted_c = c - col_start_address;
103  curr_value =
104  *(bitmap->bitmap + adjusted_r * bitmap->num_cols + adjusted_c);
105  }
106  TRY(screen_tx_cmd_or_data(screen, (uint8_t)((curr_value & 0xff00) >> 8),
107  kScreenOpTypeData));
108  TRY(screen_tx_cmd_or_data(screen, (uint8_t)(curr_value & 0x00ff),
109  kScreenOpTypeData));
110  }
111  }
112 
113  return OK_STATUS();
114 }