ssd1306.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /**
  2. * Copyright (c) 2017-2018 Tara Keeling
  3. *
  4. * This software is released under the MIT License.
  5. * https://opensource.org/licenses/MIT
  6. */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdint.h>
  10. #include <stdbool.h>
  11. #include <stdlib.h>
  12. #include <math.h>
  13. #include <esp_heap_caps.h>
  14. #include "ssd1306.h"
  15. #define COM_Disable_LR_Remap 0
  16. #define COM_Enable_LR_Remap BIT( 5 )
  17. #define COM_Pins_Sequential 0
  18. #define COM_Pins_Alternative BIT( 4 )
  19. #define COM_ScanDir_LR 0
  20. #define COM_ScanDir_RL 1
  21. static bool SSD1306_Init( struct SSD1306_Device* DeviceHandle, int Width, int Height );
  22. bool SSD1306_WriteCommand( struct SSD1306_Device* DeviceHandle, SSDCmd SSDCommand ) {
  23. NullCheck( DeviceHandle, return false );
  24. NullCheck( DeviceHandle->WriteCommand, return false );
  25. return ( DeviceHandle->WriteCommand ) ( DeviceHandle, SSDCommand );
  26. }
  27. bool SSD1306_WriteData( struct SSD1306_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
  28. NullCheck( DeviceHandle, return false );
  29. NullCheck( DeviceHandle->WriteData, return false );
  30. return ( DeviceHandle->WriteData ) ( DeviceHandle, Data, DataLength );
  31. }
  32. void SSD1306_SetMuxRatio( struct SSD1306_Device* DeviceHandle, uint8_t Ratio ) {
  33. NullCheck( DeviceHandle, return );
  34. SSD1306_WriteCommand( DeviceHandle, 0xA8 );
  35. SSD1306_WriteCommand( DeviceHandle, Ratio );
  36. }
  37. void SSD1306_SetDisplayOffset( struct SSD1306_Device* DeviceHandle, uint8_t Offset ) {
  38. NullCheck( DeviceHandle, return );
  39. SSD1306_WriteCommand( DeviceHandle, 0xD3 );
  40. SSD1306_WriteCommand( DeviceHandle, Offset );
  41. }
  42. void SSD1306_SetDisplayStartLine( struct SSD1306_Device* DeviceHandle, int Line ) {
  43. NullCheck( DeviceHandle, return );
  44. SSD1306_WriteCommand( DeviceHandle,
  45. SSDCmd_Set_Display_Start_Line + ( uint32_t ) ( Line & 0x1F )
  46. );
  47. }
  48. /*
  49. * This is all a big giant mystery that I have yet to figure out.
  50. * Beware all ye who enter.
  51. */
  52. static void SetCOMPinConfiguration( struct SSD1306_Device* DeviceHandle, uint32_t RemapCFG, uint32_t PinCFG, int ScanDir ) {
  53. NullCheck( DeviceHandle, return );
  54. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_COM_Pin_Config );
  55. SSD1306_WriteCommand( DeviceHandle, ( uint8_t ) ( RemapCFG | PinCFG | BIT( 1 ) ) );
  56. SSD1306_WriteCommand( DeviceHandle,
  57. ( ScanDir == COM_ScanDir_LR ) ? SSDCmd_Set_Display_VFlip_Off : SSDCmd_Set_Display_VFlip_On
  58. );
  59. }
  60. void SSD1306_SetContrast( struct SSD1306_Device* DeviceHandle, uint8_t Contrast ) {
  61. NullCheck( DeviceHandle, return );
  62. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Contrast );
  63. SSD1306_WriteCommand( DeviceHandle, Contrast );
  64. }
  65. void SSD1306_EnableDisplayRAM( struct SSD1306_Device* DeviceHandle ) {
  66. NullCheck( DeviceHandle, return );
  67. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Display_Show_RAM );
  68. }
  69. void SSD1306_DisableDisplayRAM( struct SSD1306_Device* DeviceHandle ) {
  70. NullCheck( DeviceHandle, return );
  71. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Display_Ignore_RAM );
  72. }
  73. void SSD1306_SetInverted( struct SSD1306_Device* DeviceHandle, bool Inverted ) {
  74. NullCheck( DeviceHandle, return );
  75. SSD1306_WriteCommand( DeviceHandle, ( Inverted == true ) ? SSDCmd_Set_Inverted_Display : SSDCmd_Set_Normal_Display );
  76. }
  77. void SSD1306_SetDisplayClocks( struct SSD1306_Device* DeviceHandle, uint32_t DisplayClockDivider, uint32_t OSCFrequency ) {
  78. NullCheck( DeviceHandle, return );
  79. DisplayClockDivider&= 0x0F;
  80. OSCFrequency&= 0x0F;
  81. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Display_CLK );
  82. SSD1306_WriteCommand( DeviceHandle, ( ( OSCFrequency << 4 ) | DisplayClockDivider ) );
  83. }
  84. /* There is no documentation for this command, but it is required during init. */
  85. static void EnableChargePumpRegulator( struct SSD1306_Device* DeviceHandle ) {
  86. NullCheck( DeviceHandle, return );
  87. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Enable_Charge_Pump_Regulator );
  88. SSD1306_WriteCommand( DeviceHandle, 0x14 ); /* MAGIC NUMBER */
  89. }
  90. void SSD1306_DisplayOn( struct SSD1306_Device* DeviceHandle ) {
  91. NullCheck( DeviceHandle, return );
  92. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Display_On );
  93. }
  94. void SSD1306_DisplayOff( struct SSD1306_Device* DeviceHandle ) {
  95. NullCheck( DeviceHandle, return );
  96. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Display_Off );
  97. }
  98. void SSD1306_SetDisplayAddressMode( struct SSD1306_Device* DeviceHandle, SSD1306_AddressMode AddressMode ) {
  99. NullCheck( DeviceHandle, return );
  100. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Memory_Addressing_Mode );
  101. SSD1306_WriteCommand( DeviceHandle, AddressMode );
  102. }
  103. void SSD1306_Update( struct SSD1306_Device* DeviceHandle ) {
  104. NullCheck( DeviceHandle, return );
  105. SSD1306_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1);
  106. SSD1306_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
  107. SSD1306_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
  108. }
  109. void SSD1306_WriteRawData( struct SSD1306_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
  110. NullCheck( DeviceHandle, return );
  111. NullCheck( Data, return );
  112. DataLength = DataLength > DeviceHandle->FramebufferSize ? DeviceHandle->FramebufferSize : DataLength;
  113. if ( DataLength > 0 ) {
  114. SSD1306_WriteData( DeviceHandle, Data, DataLength );
  115. }
  116. }
  117. void SSD1306_SetHFlip( struct SSD1306_Device* DeviceHandle, bool On ) {
  118. NullCheck( DeviceHandle, return );
  119. SSD1306_WriteCommand( DeviceHandle, ( On == true ) ? SSDCmd_Set_Display_HFlip_On : SSDCmd_Set_Display_HFlip_Off );
  120. }
  121. void SSD1306_SetVFlip( struct SSD1306_Device* DeviceHandle, bool On ) {
  122. NullCheck( DeviceHandle, return );
  123. SSD1306_WriteCommand( DeviceHandle, ( On == true ) ? SSDCmd_Set_Display_VFlip_On : SSDCmd_Set_Display_VFlip_Off );
  124. }
  125. void SSD1306_SetColumnAddress( struct SSD1306_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
  126. NullCheck( DeviceHandle, return );
  127. CheckBounds( Start > SSD1306_Max_Col, return );
  128. CheckBounds( End > SSD1306_Max_Col, return );
  129. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Column_Address );
  130. SSD1306_WriteCommand( DeviceHandle, Start );
  131. SSD1306_WriteCommand( DeviceHandle, End );
  132. }
  133. void SSD1306_SetPageAddress( struct SSD1306_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
  134. NullCheck( DeviceHandle, return );
  135. CheckBounds( Start > SSD1306_Max_Row, return );
  136. CheckBounds( End > SSD1306_Max_Row, return );
  137. SSD1306_WriteCommand( DeviceHandle, SSDCmd_Set_Page_Address );
  138. SSD1306_WriteCommand( DeviceHandle, Start );
  139. SSD1306_WriteCommand( DeviceHandle, End );
  140. }
  141. bool SSD1306_HWReset( struct SSD1306_Device* DeviceHandle ) {
  142. NullCheck( DeviceHandle, return 0 );
  143. if ( DeviceHandle->Reset != NULL ) {
  144. return ( DeviceHandle->Reset ) ( DeviceHandle );
  145. }
  146. /* This should always return true if there is no reset callback as
  147. * no error would have occurred during the non existant reset.
  148. */
  149. return true;
  150. }
  151. static bool SSD1306_Init( struct SSD1306_Device* DeviceHandle, int Width, int Height ) {
  152. DeviceHandle->Width = Width;
  153. DeviceHandle->Height = Height;
  154. DeviceHandle->FramebufferSize = ( DeviceHandle->Width * Height ) / 8;
  155. // DeviceHandle->Framebuffer = heap_caps_calloc( 1, DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL );
  156. DeviceHandle->Framebuffer = calloc( 1, DeviceHandle->FramebufferSize );
  157. NullCheck( DeviceHandle->Framebuffer, return false );
  158. /* For those who have a hardware reset pin on their display */
  159. SSD1306_HWReset( DeviceHandle );
  160. /* Init sequence according to SSD1306.pdf */
  161. SSD1306_SetMuxRatio( DeviceHandle, Height - 1 );
  162. SSD1306_SetDisplayOffset( DeviceHandle, 0x00 );
  163. SSD1306_SetDisplayStartLine( DeviceHandle, 0 );
  164. SSD1306_SetHFlip( DeviceHandle, false );
  165. SSD1306_SetVFlip( DeviceHandle, false );
  166. if ( Height == 64 ) {
  167. SetCOMPinConfiguration( DeviceHandle, COM_Disable_LR_Remap, COM_Pins_Alternative, COM_ScanDir_LR );
  168. } else {
  169. SetCOMPinConfiguration( DeviceHandle, COM_Disable_LR_Remap, COM_Pins_Sequential, COM_ScanDir_LR );
  170. }
  171. SSD1306_SetContrast( DeviceHandle, 0x7F );
  172. SSD1306_DisableDisplayRAM( DeviceHandle );
  173. SSD1306_SetInverted( DeviceHandle, false );
  174. SSD1306_SetDisplayClocks( DeviceHandle, 0, 8 );
  175. EnableChargePumpRegulator( DeviceHandle );
  176. SSD1306_SetDisplayAddressMode( DeviceHandle, AddressMode_Vertical );
  177. SSD1306_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1 );
  178. SSD1306_SetPageAddress( DeviceHandle, 0, ( DeviceHandle->Height / 8 ) - 1 );
  179. SSD1306_EnableDisplayRAM( DeviceHandle );
  180. SSD1306_DisplayOn( DeviceHandle );
  181. SSD1306_Update( DeviceHandle );
  182. return true;
  183. }
  184. bool SSD1306_Init_I2C( struct SSD1306_Device* DeviceHandle, int Width, int Height, int I2CAddress, int ResetPin, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset ) {
  185. NullCheck( DeviceHandle, return false );
  186. NullCheck( WriteCommand, return false );
  187. NullCheck( WriteData, return false );
  188. memset( DeviceHandle, 0, sizeof( struct SSD1306_Device ) );
  189. DeviceHandle->WriteCommand = WriteCommand;
  190. DeviceHandle->WriteData = WriteData;
  191. DeviceHandle->Reset = Reset;
  192. DeviceHandle->Address = I2CAddress;
  193. DeviceHandle->RSTPin = ResetPin;
  194. return SSD1306_Init( DeviceHandle, Width, Height );
  195. }
  196. bool SSD1306_Init_SPI( struct SSD1306_Device* DeviceHandle, int Width, int Height, int ResetPin, int CSPin, spi_device_handle_t SPIHandle, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset ) {
  197. NullCheck( DeviceHandle, return false );
  198. NullCheck( WriteCommand, return false );
  199. NullCheck( WriteData, return false );
  200. memset( DeviceHandle, 0, sizeof( struct SSD1306_Device ) );
  201. DeviceHandle->WriteCommand = WriteCommand;
  202. DeviceHandle->WriteData = WriteData;
  203. DeviceHandle->Reset = Reset;
  204. DeviceHandle->SPIHandle = SPIHandle;
  205. DeviceHandle->RSTPin = ResetPin;
  206. DeviceHandle->CSPin = CSPin;
  207. return SSD1306_Init( DeviceHandle, Width, Height );
  208. }