Software APIs
teacup_leds_and_screen_demo.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 "dt/dt_api.h" // Generated
6 #include "sw/device/examples/teacup_demos/data/bitmaps.h"
8 #include "sw/device/lib/boards/teacup_v1_3_0/leds.h"
12 #include "sw/device/lib/peripherals/ssd1131_screen.h"
15 #include "sw/device/lib/testing/i2c_testutils.h"
16 #include "sw/device/lib/testing/pinmux_testutils.h"
17 #include "sw/device/lib/testing/test_framework/check.h"
19 
21 
22 OTTF_DEFINE_TEST_CONFIG();
23 
24 /**
25  * OT Peripheral Handles.
26  */
27 static dif_i2c_t i2c;
28 static dif_gpio_t gpio;
29 static dif_pinmux_t pinmux;
30 static dif_spi_host_t spi_host;
31 static screen_t screen;
32 
33 /**
34  * Defined Constants.
35  */
36 enum {
37  // Demo Control
38  kDemoNumCycles = 50,
39 
40  // LED Control
41  kLedNumColorsInCycle = 4,
42  kLedCyclePauseMilliseconds = 500,
43  kLedBrightnessLowPercent = 5,
44  kLedBrightnessHighPercent = 40,
45  kLedBrightnessStepPercent = 5,
46 
47  // Screen Control
48  kScreenSpiDataCommandGpio = 1,
49  kScreenBitmapsInCycle = 1,
50 };
51 
52 static const led_rgb_color_t kLedColorBlue = {
53  .r = 0x33,
54  .g = 0x69,
55  .b = 0xE8,
56 };
57 
58 static const led_rgb_color_t kLedColorRed = {
59  .r = 0xD5,
60  .g = 0x0F,
61  .b = 0x25,
62 };
63 
64 static const led_rgb_color_t kLedColorYellow = {
65  .r = 0xEE,
66  .g = 0xB2,
67  .b = 0x11,
68 };
69 
70 static const led_rgb_color_t kLedColorGreen = {
71  .r = 0x00,
72  .g = 0x99,
73  .b = 0x25,
74 };
75 
76 /**
77  * Pinmux pad attributes for the SPI host pins.
78  */
79 static const pinmux_pad_attributes_t kPinmuxPadAttrs[] = {
80  {
81  .pad = kDtPadIoa2, // CS
82  .flags = kDifPinmuxPadAttrPullResistorEnable |
83  kDifPinmuxPadAttrPullResistorUp,
84  },
85  {
86  .pad = kDtPadIob7, // SCK
87  .flags = kDifPinmuxPadAttrPullResistorEnable |
88  kDifPinmuxPadAttrPullResistorUp,
89  },
90  {
91  .pad = kDtPadIob2, // SD0
92  .flags = kDifPinmuxPadAttrPullResistorEnable |
93  kDifPinmuxPadAttrPullResistorUp,
94  },
95 };
96 
97 /**
98  * Screen bitmaps.
99  */
100 const screen_bitmap_t *kScreenBitmaps[kScreenBitmapsInCycle] = {
101  &kOtLogoBitmap,
102 };
103 
104 static status_t peripheral_init(void) {
105  // Initialize DIFs.
106  TRY(dif_i2c_init(mmio_region_from_addr(TOP_EARLGREY_I2C0_BASE_ADDR), &i2c));
107  TRY(dif_gpio_init(mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR), &gpio));
109  &pinmux));
111  &spi_host));
112 
113  // Initialize Screen.
114  screen.gpio = &gpio;
115  screen.spi_host = &spi_host;
116  screen.data_command_gpio = kScreenSpiDataCommandGpio;
117 
118  // Initialize pinmux for LED I2C.
127 
128  // Initialize pinmux for Screen SPI (CS, SCK, data out).
135 
136  // Initialize pinmux for Screen GPIOs (IOC6 and 9).
141 
142  // Pinmux pad configurations.
143  pinmux_testutils_configure_pads(&pinmux, kPinmuxPadAttrs,
144  ARRAYSIZE(kPinmuxPadAttrs));
145 
146  return OK_STATUS();
147 }
148 
149 static status_t configure_led_i2c_controller(void) {
151  TRY(i2c_testutils_set_speed(&i2c, kDifI2cSpeedFastPlus));
152  TRY(leds_i2c_controller_configure(&i2c));
153  return OK_STATUS();
154 }
155 
156 static status_t configure_screen_spi_controller(void) {
157  dif_spi_host_config_t config = {
158  .spi_clock = 10000000,
159  .peripheral_clock_freq_hz = (uint32_t)kClockFreqPeripheralHz,
160  .chip_select =
161  {
162  .idle = 1,
163  .trail = 1,
164  .lead = 1,
165  },
166  .full_cycle = 0,
167  .cpha = 0,
168  .cpol = 0,
169  .tx_watermark = 0,
170  .rx_watermark = 0,
171  };
172  TRY(dif_gpio_write(&gpio, screen.data_command_gpio, false));
175  TRY(dif_spi_host_configure(&spi_host, config));
176  TRY(dif_spi_host_output_set_enabled(&spi_host, true));
177  return OK_STATUS();
178 }
179 
180 static status_t setup_screen(void) {
181  TRY(screen_toggle_power(&screen, /*on=*/true));
182  TRY(screen_toggle_pixel_mode(&screen, kScreenPixelModeNormal));
183  TRY(screen_configure_color_format(&screen, kScreenColorFormat65k2Byte));
184  TRY(screen_tx_cmd_or_data(&screen, kScreenDeactivateScrolling,
185  kScreenOpTypeCommand));
186  TRY(screen_set_column_address_range(&screen, 0, kScreenMaxCols - 1));
187  TRY(screen_set_row_address_range(&screen, 0, kScreenMaxRows - 1));
188  return OK_STATUS();
189 }
190 
191 bool test_main(void) {
192  // Setup OT and peripherals.
193  CHECK_STATUS_OK(peripheral_init());
194  CHECK_STATUS_OK(configure_led_i2c_controller());
195  CHECK_STATUS_OK(configure_screen_spi_controller());
196  CHECK_STATUS_OK(setup_screen());
197  CHECK_STATUS_OK(leds_turn_all_on(&i2c));
198 
199  // LED brightness levels and colors.
200  uint8_t brightness_start =
201  (uint8_t)((float)0xFF * (float)kLedBrightnessLowPercent / 100.0);
202  uint8_t brightness_end =
203  (uint8_t)((float)0xFF * (float)kLedBrightnessHighPercent / 100.0);
204  uint8_t brightness_step =
205  (uint8_t)((float)0xFF * (float)kLedBrightnessStepPercent / 100.0);
206  uint8_t curr_brightness = brightness_start;
207  const led_rgb_color_t kColorCycle[kLedNumColorsInCycle] = {
208  kLedColorBlue,
209  kLedColorRed,
210  kLedColorYellow,
211  kLedColorGreen,
212  };
213 
214  // Cycle through brightness levels and colors.
215  for (size_t i = 0; i < kDemoNumCycles; ++i) {
216  for (size_t j = 0; j < kLedNumColorsInCycle; ++j) {
217  CHECK_STATUS_OK(
218  leds_set_color(&i2c, (i + j) % kNumTeacupLeds, kColorCycle[j]));
219  }
220  CHECK_STATUS_OK(leds_set_all_brightness(&i2c, curr_brightness));
221  CHECK_STATUS_OK(
222  screen_draw_bitmap(&screen, kScreenBitmaps[i % kScreenBitmapsInCycle]));
223  curr_brightness += brightness_step;
224  if (curr_brightness >= brightness_end ||
225  curr_brightness <= brightness_start) {
226  brightness_step *= -1;
227  }
228  busy_spin_micros(kLedCyclePauseMilliseconds * 1000);
229  }
230 
231  // Turn screen and LEDs off.
232  CHECK_STATUS_OK(screen_toggle_power(&screen, /*on=*/false));
233  CHECK_STATUS_OK(leds_turn_all_off(&i2c));
234 
235  return true;
236 }