LCOV - code coverage report
Current view: top level - AP_Notify - Display_SSD1306_I2C.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 47 0.0 %
Date: 2026-09-09 11:02:08 Functions: 0 10 0.0 %

          Line data    Source code
       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_SSD1306_I2C.h"
      16             : 
      17             : #include <AP_HAL/AP_HAL.h>
      18             : #include <AP_HAL/Device.h>
      19             : 
      20             : // constructor
      21           0 : Display_SSD1306_I2C::Display_SSD1306_I2C(AP_HAL::Device &_dev) :
      22           0 :     dev(_dev)
      23             : {
      24           0 : }
      25             : 
      26           0 : Display_SSD1306_I2C::~Display_SSD1306_I2C()
      27             : {
      28           0 : }
      29             : 
      30             : 
      31           0 : Display_Backend *Display_SSD1306_I2C::probe(AP_HAL::Device &_dev)
      32             : {
      33           0 :     Display_SSD1306_I2C *driver = NEW_NOTHROW Display_SSD1306_I2C(_dev);
      34           0 :     if (!driver || !driver->hw_init()) {
      35           0 :         delete driver;
      36           0 :         return nullptr;
      37             :     }
      38           0 :     return driver;
      39             : }
      40             : 
      41           0 : bool Display_SSD1306_I2C::hw_init()
      42             : {
      43             :     struct PACKED {
      44             :         uint8_t reg;
      45             :         uint8_t seq[31];
      46           0 :     } init_seq = { 0x0,  {
      47             :                           // LEGEND:
      48             :                           //    *** is out of sequence for init steps recommended in datasheet
      49             :                           //    +++ not listed in sequence for init steps recommended in datasheet
      50             : 
      51             :             0xAE,         // Display OFF
      52             :             0xD5, 0x80,   // *** Set Display Clock Divide Ratio and Oscillator Frequency
      53             :                           //    Clock Divide Ratio: 0b (== 1)
      54             :                           //    Oscillator Frequency: 1000b (== +0%)
      55             :             0xA8, 0x3F,   // MUX Ratio: 111111b (== 64MUX)
      56             :             0xD3, 0x00,   // Display Offset: 0b (== 0)
      57             :             0x40,         // Display Start Line: 0b (== 0)
      58             :             0x8D, 0x14,   // *** Enable charge pump regulator: 1b (== Enable)
      59             :             0x20, 0x00,   // *** Memory Addressing Mode: 00b (== Horizontal Addressing Mode)
      60             :             0xA1,         // Segment re-map: 1b (== column address 127 is mapped to SEG0)
      61             :             0xC8,         // COM Output Scan Direction: 1b (== remapped mode. Scan from COM[N-1] to COM0)
      62             :             0xDA, 0x12,   // COM Pins hardware configuration: 01b (POR)
      63             :                           //    (== Alternative COM pin configuration + Disable COM Left/Right remap)
      64             :             0x81, 0xCF,   // Contrast Control: 0xCF (== 207 decimal, range 0..255)
      65             :             0xD9, 0xF1,   // +++ Pre-charge Period: 0xF1 (== 1 DCLK P1 + 15 DCLK P2)
      66             :             0xDB, 0x40,   // +++ VCOMH Deselect Level: 100b (INVALID?!) (== ?!)
      67             :             0xA4,         // Entire Display ON (ignoring RAM): (== OFF)
      68             :             0xA6,         // Normal/Inverse Display: 0b (== Normal)
      69             :             0xAF,         // Display ON: 1b (== ON)
      70             :             0x21, 0, 127, // +++ Column Address: (== start:0, end:127)
      71             :             0x22, 0, 7    // +++ Page Address: (== start:0, end:7)
      72             :     } };
      73             : 
      74             :     // take i2c bus semaphore
      75           0 :     WITH_SEMAPHORE(dev.get_semaphore());
      76             : 
      77             :     // init display
      78           0 :     bool success = dev.transfer((uint8_t *)&init_seq, sizeof(init_seq), nullptr, 0);
      79           0 :     if (success) {
      80           0 :         _need_hw_update = true;
      81           0 :         dev.register_periodic_callback(20000, FUNCTOR_BIND_MEMBER(&Display_SSD1306_I2C::_timer, void));
      82             :     }
      83             : 
      84           0 :     return success;
      85           0 : }
      86             : 
      87           0 : void Display_SSD1306_I2C::hw_update()
      88             : {
      89           0 :     _need_hw_update = true;
      90           0 : }
      91             : 
      92           0 : void Display_SSD1306_I2C::_timer()
      93             : {
      94           0 :     if (!_need_hw_update) {
      95           0 :         return;
      96             :     }
      97           0 :     _need_hw_update = false;
      98             : 
      99             :     struct PACKED {
     100             :         uint8_t reg;
     101             :         uint8_t cmd[6];
     102           0 :     } command = { 0x0, {0x21, 0, 127, 0x22, 0, 7} };
     103             : 
     104             :     struct PACKED {
     105             :         uint8_t reg;
     106             :         uint8_t db[SSD1306_COLUMNS/2];
     107           0 :     } display_buffer = { 0x40, {} };
     108             : 
     109             :     // write buffer to display
     110           0 :     for (uint8_t i = 0; i < (SSD1306_ROWS / SSD1306_ROWS_PER_PAGE); i++) {
     111           0 :         command.cmd[4] = i;
     112           0 :         dev.transfer((uint8_t *)&command, sizeof(command), nullptr, 0);
     113             : 
     114           0 :         memcpy(&display_buffer.db[0], &_displaybuffer[i * SSD1306_COLUMNS], SSD1306_COLUMNS/2);
     115           0 :         dev.transfer((uint8_t *)&display_buffer, SSD1306_COLUMNS/2 + 1, nullptr, 0);
     116             : 
     117           0 :         memcpy(&display_buffer.db[0], &_displaybuffer[i * SSD1306_COLUMNS + SSD1306_COLUMNS/2 ], SSD1306_COLUMNS/2);
     118           0 :         dev.transfer((uint8_t *)&display_buffer, SSD1306_COLUMNS/2 + 1, nullptr, 0);
     119             :     }
     120             : }
     121             : 
     122           0 : void Display_SSD1306_I2C::set_pixel(uint16_t x, uint16_t y)
     123             : {
     124             :     // check x, y range
     125           0 :     if ((x >= SSD1306_COLUMNS) || (y >= SSD1306_ROWS)) {
     126           0 :         return;
     127             :     }
     128             :     // set pixel in buffer
     129           0 :     _displaybuffer[x + (y / 8 * SSD1306_COLUMNS)] |= 1 << (y % 8);
     130             : }
     131             : 
     132           0 : void Display_SSD1306_I2C::clear_pixel(uint16_t x, uint16_t y)
     133             : {
     134             :     // check x, y range
     135           0 :     if ((x >= SSD1306_COLUMNS) || (y >= SSD1306_ROWS)) {
     136           0 :         return;
     137             :     }
     138             :     // clear pixel in buffer
     139           0 :     _displaybuffer[x + (y / 8 * SSD1306_COLUMNS)] &= ~(1 << (y % 8));
     140             : }
     141             : 
     142           0 : void Display_SSD1306_I2C::clear_screen()
     143             : {
     144           0 :      memset(_displaybuffer, 0, SSD1306_COLUMNS * SSD1306_ROWS_PER_PAGE);
     145           0 : }

Generated by: LCOV version 1.14