APM:Libraries
Display_SH1106_I2C.cpp
Go to the documentation of this file.
1 /*
2  This program is free software: you can redistribute it and/or modify
3  it under the terms of the GNU General Public License as published by
4  the Free Software Foundation, either version 3 of the License, or
5  (at your option) any later version.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program. If not, see <http://www.gnu.org/licenses/>.
14  */
15 #include "Display_SH1106_I2C.h"
16 
17 #include <utility>
18 
19 #include <AP_HAL/AP_HAL.h>
20 #include <AP_HAL/I2CDevice.h>
21 
22 // constructor
24  _dev(std::move(dev))
25 {
26 }
27 
29 {
30 }
31 
33 {
34  Display_SH1106_I2C *driver = new Display_SH1106_I2C(std::move(dev));
35  if (!driver || !driver->hw_init()) {
36  delete driver;
37  return nullptr;
38  }
39  return driver;
40 }
41 
42 
44 {
45  struct PACKED {
46  uint8_t reg;
47  uint8_t seq[26];
48  } init_seq = { 0x0, {
49  0xAE, // Display OFF
50  0xA1, // Segment re-map
51  0xC8, // COM Output Scan Direction
52  0xA8, 0x3F, // MUX Ratio
53  0xD5, 0x50, // Display Clock Divide Ratio and Oscillator Frequency: (== +0%)
54  0xD3, 0x00, // Display Offset
55  0xDB, 0x40, // VCOMH Deselect Level
56  0x81, 0xCF, // Contrast Control
57  0xAD, 0x8B, // DC-DC Control Mode: 1b (== internal DC-DC enabled) (AKA: Enable charge pump regulator)
58  0x40, // Display Start Line
59  0xDA, 0x12, // +++ COM Pins hardware configuration
60  0xD9, 0xF1, // +++ Pre-charge Period
61  0xA4, // +++ Entire Display ON (ignoring RAM): 0b (== OFF)
62  0xA6, // +++ Normal/Inverse Display: 0b (== Normal)
63  0xAF, // Display ON
64  0xB0, // Page Address
65  0x02, 0x10 // Column Address
66  } };
67 
69 
70  // take i2c bus semaphore
72  return false;
73  }
74 
75  // init display
76  bool success = _dev->transfer((uint8_t *)&init_seq, sizeof(init_seq), nullptr, 0);
77 
78  // give back i2c semaphore
79  _dev->get_semaphore()->give();
80 
81  if (success) {
82  _need_hw_update = true;
84  }
85 
86  return success;
87 }
88 
90 {
91  _need_hw_update = true;
92 }
93 
95 {
96  if (!_need_hw_update) {
97  return;
98  }
99  _need_hw_update = false;
100 
101  struct PACKED {
102  uint8_t reg;
103  uint8_t column_0_3;
104  uint8_t column_4_7;
105  uint8_t page;
106  } command = { 0x0, 0x2, 0x10, 0xB0 };
107 
108  struct PACKED {
109  uint8_t reg;
110  uint8_t db[SH1106_COLUMNS/2];
111  } display_buffer = { 0x40, {} };
112 
113  // write buffer to display
114  for (uint8_t i = 0; i < (SH1106_ROWS / SH1106_ROWS_PER_PAGE); i++) {
115  command.page = 0xB0 | (i & 0x0F);
116  _dev->transfer((uint8_t *)&command, sizeof(command), nullptr, 0);
117 
118  memcpy(&display_buffer.db[0], &_displaybuffer[i * SH1106_COLUMNS], SH1106_COLUMNS/2);
119  _dev->transfer((uint8_t *)&display_buffer, SH1106_COLUMNS/2 + 1, nullptr, 0);
120  memcpy(&display_buffer.db[0], &_displaybuffer[i * SH1106_COLUMNS + SH1106_COLUMNS/2 ], SH1106_COLUMNS/2);
121  _dev->transfer((uint8_t *)&display_buffer, SH1106_COLUMNS/2 + 1, nullptr, 0);
122  }
123 }
124 
125 void Display_SH1106_I2C::set_pixel(uint16_t x, uint16_t y)
126 {
127  // check x, y range
128  if ((x >= SH1106_COLUMNS) || (y >= SH1106_ROWS)) {
129  return;
130  }
131  // set pixel in buffer
132  _displaybuffer[x + (y / 8 * SH1106_COLUMNS)] |= 1 << (y % 8);
133 }
134 
135 void Display_SH1106_I2C::clear_pixel(uint16_t x, uint16_t y)
136 {
137  // check x, y range
138  if ((x >= SH1106_COLUMNS) || (y >= SH1106_ROWS)) {
139  return;
140  }
141  // clear pixel in buffer
142  _displaybuffer[x + (y / 8 * SH1106_COLUMNS)] &= ~(1 << (y % 8));
143 }
144 
146 {
148 }
#define SH1106_ROWS
void clear_screen() override
virtual PeriodicHandle register_periodic_callback(uint32_t period_usec, PeriodicCb)=0
Display_SH1106_I2C(AP_HAL::OwnPtr< AP_HAL::Device > dev)
virtual AP_HAL::Semaphore * get_semaphore()=0
#define HAL_SEMAPHORE_BLOCK_FOREVER
Definition: Semaphores.h:5
virtual bool take(uint32_t timeout_ms) WARN_IF_UNUSED=0
void clear_pixel(uint16_t x, uint16_t y) override
AP_HAL::OwnPtr< AP_HAL::Device > _dev
#define SH1106_ROWS_PER_PAGE
#define x(i)
void hw_update() override
bool hw_init() override
static AP_HAL::OwnPtr< AP_HAL::Device > dev
Definition: ICM20789.cpp:16
uint8_t _displaybuffer[SH1106_COLUMNS *SH1106_ROWS_PER_PAGE]
virtual bool give()=0
virtual bool transfer(const uint8_t *send, uint32_t send_len, uint8_t *recv, uint32_t recv_len)=0
#define PACKED
Definition: AP_Common.h:28
#define FUNCTOR_BIND_MEMBER(func, rettype,...)
Definition: functor.h:31
static Display_SH1106_I2C * probe(AP_HAL::OwnPtr< AP_HAL::Device > dev)
#define SH1106_COLUMNS
void set_pixel(uint16_t x, uint16_t y) override