SSD1327.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #include "font8x8_basic.h"
  2. #include "font16x16.h"
  3. #include "font16x32.h"
  4. #include "SSD1327.h"
  5. #include "cmsis_os.h"
  6. #include <stdint.h>
  7. #include <stdio.h>
  8. extern "C" {
  9. #include "OLED_SSD1327.h"
  10. }
  11. #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
  12. #define bitSet(value, bit) ((value) |= (1UL << (bit)))
  13. #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
  14. #define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
  15. #define _max(a,b) ((a)>(b)?(a):(b))
  16. #define _min(a,b) ((a)<(b)?(a):(b))
  17. #define abs(x) ((x)>0?(x):-(x))
  18. extern uint8_t buffer[];
  19. //#define frameBuffer buffer[];
  20. //SSD1327 ssd1327(0, 0, 0);
  21. SSD1327::SSD1327(int cs, int dc, int rst) {
  22. frameBuffer = buffer;
  23. }
  24. //
  25. void SSD1327::writeCmd(uint8_t reg){//Writes a command byte to the driver
  26. SSD1327_Command(reg);
  27. }
  28. //
  29. void SSD1327::writeData(uint8_t data){//Writes 1 byte to the display's memory
  30. SSD1327_Data(data);
  31. }
  32. //
  33. void SSD1327::setWriteZone(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) { //defines a rectangular area of memory which the driver will itterate through. This function takes memory locations, meaning a 64x128 space
  34. writeCmd(0x15); //Set Column Address
  35. writeCmd(x1); //Beginning. Note that you must divide the column by 2, since 1 byte in memory is 2 pixels
  36. writeCmd(x2); //End
  37. writeCmd(0x75); //Set Row Address
  38. writeCmd(y1); //Beginning
  39. writeCmd(y2); //End
  40. }
  41. //
  42. uint16_t SSD1327::coordsToAddress(uint8_t x, uint8_t y){ //Converts a pixel location to a linear memory address
  43. return (x/2)+(y*64);
  44. }
  45. //
  46. void SSD1327::setPixelChanged(uint8_t x, uint8_t y, bool changed){
  47. uint16_t targetByte = coordsToAddress(x, y)/8;
  48. bitWrite(changedPixels[targetByte], coordsToAddress(x, y) % 8, changed);
  49. }
  50. //
  51. void SSD1327::drawPixel(uint8_t x, uint8_t y, uint8_t color, bool display){//pixel xy coordinates 0-127, color 0-15, and whether to immediately output it to the display or buffer it
  52. int address = coordsToAddress(x,y);
  53. if((x%2) == 0){//If this is an even pixel, and therefore needs shifting to the more significant nibble
  54. frameBuffer[address] = (frameBuffer[address] & 0x0f) | (color<<4);
  55. } else {
  56. frameBuffer[address] = (frameBuffer[address] & 0xf0) | (color);
  57. }
  58. if(display){
  59. setWriteZone(x/2,y,x/2,y);
  60. writeData(frameBuffer[address]);
  61. setPixelChanged(x, y, false); // We've now synced the display with this byte of the buffer, no need to write it again
  62. } else {
  63. setPixelChanged(x, y, true); // This pixel is due for an update next refresh
  64. }
  65. }
  66. //
  67. void SSD1327::drawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color, bool display){//Draws a rectangle from x1,y1 to x2,y2.
  68. uint8_t xMin = _min(x1, x2); // TODO: double performance by writing whole bytes at a time
  69. uint8_t xMax = _max(x1, x2);
  70. uint8_t yMin = _min(y1, y2);
  71. uint8_t yMax = _max(y1, y2);
  72. for (uint8_t x = xMin; x <= xMax; x++) {
  73. for (uint8_t y = yMin; y <= yMax; y++) {
  74. drawPixel(x, y, color, display);
  75. }
  76. }
  77. }
  78. //
  79. void SSD1327::drawHLine(int x, int y, int length, uint8_t color, bool display){
  80. for (uint8_t i = x; i < x+length; i++) {
  81. drawPixel(i, y, color, display);
  82. }
  83. }
  84. void SSD1327::drawVLine(int x, int y, int length, uint8_t color, bool display){
  85. for (uint8_t i = y; i < y+length; i++) {
  86. drawPixel(x, i, color, display);
  87. }
  88. }
  89. void SSD1327::drawLine(int x0, int y0, int x1, int y1, uint8_t color, bool display){ //Bresenham's line algorithm
  90. int deltaX = abs(x1-x0);
  91. int deltaY = abs(y1-y0);
  92. int signX = x0<x1 ? 1 : -1;
  93. int signY = y0<y1 ? 1 : -1;
  94. int error = (deltaX>deltaY ? deltaX : -deltaY)/2, error2;
  95. while (true) {
  96. drawPixel(x0, y0, color, display);
  97. if (x0==x1 && y0==y1) break;
  98. error2 = error;
  99. if (error2 >-deltaX) { error -= deltaY; x0 += signX; }
  100. if (error2 < deltaY) { error += deltaX; y0 += signY; }
  101. }
  102. }
  103. //
  104. void SSD1327::drawByteAsRow(uint8_t x, uint8_t y, uint8_t byte, uint8_t color){//Draws a byte as an 8 pixel row
  105. for (int i = 0; i < 8; i++) {
  106. if(bitRead(byte, i)){
  107. drawPixel(x+i, y, color, false);
  108. }
  109. }
  110. }
  111. //
  112. void SSD1327::drawChar(uint8_t x, uint8_t y, char thisChar, uint8_t color){
  113. for (size_t i = 0; i < 8; i++) {
  114. drawByteAsRow(x, y+i, font8x8_basic[(unsigned char)thisChar][i], color);
  115. }
  116. }
  117. //
  118. void SSD1327::drawCharArray(uint8_t x, uint8_t y, char text[], uint8_t color, int size){
  119. const char* thisChar;
  120. uint8_t xOffset = 0;
  121. if(size==16){
  122. for (thisChar = text; *thisChar != '\0'; thisChar++) {
  123. drawChar16(x+xOffset, y, *thisChar, color);
  124. xOffset += 8;
  125. }
  126. } else if(size==32){
  127. for (thisChar = text; *thisChar != '\0'; thisChar++) {
  128. drawChar32(x+xOffset, y, *thisChar, color);
  129. xOffset += 16;
  130. }
  131. }
  132. else {
  133. for (thisChar = text; *thisChar != '\0'; thisChar++) {
  134. drawChar(x+xOffset, y, *thisChar, color);
  135. xOffset += 8;
  136. }
  137. }
  138. }
  139. //
  140. void SSD1327::drawString(uint8_t x, uint8_t y, char *textString, uint8_t color, int size){
  141. char text[64] = {0};
  142. sprintf(text, "%s", textString);
  143. //textString.toCharArray(text, 64);
  144. drawCharArray(x,y, text, color, size);
  145. }
  146. void SSD1327::drawChar16(uint8_t x, uint8_t y, char thisChar, uint8_t color){
  147. for (size_t row = 0; row < 16; row++) {
  148. drawByteAsRow(x, y+row, font16x16[(unsigned char)thisChar][row*2], color);
  149. drawByteAsRow(x+8, y+row, font16x16[(unsigned char)thisChar][(row*2)+1], color);
  150. }
  151. }
  152. void SSD1327::drawChar32(uint8_t x, uint8_t y, char thisChar, uint8_t color){
  153. for (size_t row = 0; row < 32; row++) {
  154. drawByteAsRow(x, y+row, font16x32[(unsigned char)thisChar][row*2], color);
  155. drawByteAsRow(x+8, y+row, font16x32[(unsigned char)thisChar][(row*2)+1], color);
  156. }
  157. }
  158. void SSD1327::fillStripes(uint8_t offset){ //gradient test pattern
  159. for(int i = 0; i < 8192; i++){
  160. uint8_t color = ((i+offset) & 0xF) | (((i+offset) & 0xF)<<4);
  161. frameBuffer[i] = color;
  162. }
  163. for (uint16_t i = 0; i < 1024; i++) {
  164. changedPixels[i] = 0xFF; // Set all pixels to be updated next frame. fillStripes should not be used without a full write anyways, but just in case
  165. }
  166. }
  167. void SSD1327::setupScrolling(uint8_t startRow, uint8_t endRow, uint8_t startCol, uint8_t endCol, uint8_t scrollSpeed, bool right){
  168. uint8_t swap;
  169. if (startRow > endRow) { // Ensure start row is before end
  170. swap = startRow;
  171. startRow = endRow;
  172. endRow = swap;
  173. }
  174. if (startCol > endCol) { // Ditto for columns
  175. swap = startCol;
  176. startCol = endCol;
  177. endCol = swap;
  178. }
  179. writeCmd(0x2E); // Deactivate scrolling before changing anything
  180. if (right) {
  181. writeCmd(0x26); // Scroll right
  182. } else {
  183. writeCmd(0x27); // Scroll left
  184. }
  185. writeCmd(0); // Dummy byte
  186. writeCmd(startRow);
  187. writeCmd(scrollSpeed);
  188. writeCmd(endRow);
  189. writeCmd(startCol);
  190. writeCmd(endCol);
  191. writeCmd(0); // Dummy byte
  192. };
  193. void SSD1327::startScrolling(){
  194. writeCmd(0x2F);
  195. }
  196. void SSD1327::stopScrolling(){
  197. writeCmd(0x2E);
  198. }
  199. void SSD1327::scrollStep(uint8_t startRow, uint8_t endRow, uint8_t startCol, uint8_t endCol, bool right){
  200. setupScrolling(startRow, endRow, startCol, endCol, SSD1327_SCROLL_2, right);
  201. startScrolling();
  202. //delay(15);
  203. osDelay(15);
  204. stopScrolling();
  205. }
  206. void SSD1327::clearBuffer(){//
  207. for(int i = 0; i < 8192; i++){
  208. if (frameBuffer[i]) { // If there is a non-zero (non-black) byte here, make sure it gets updated
  209. frameBuffer[i] = 0;
  210. bitWrite(changedPixels[i/8], i%8, 1); // Mark this pixel as needing an update
  211. }
  212. }
  213. }
  214. void SSD1327::writeFullBuffer(){ //Outputs the full framebuffer to the display
  215. setWriteZone(0,0,63,127); //Full display
  216. for(int i = 0; i < 8192; i++){
  217. writeData(frameBuffer[i]);
  218. }
  219. for (uint16_t i = 0; i < 1024; i++) {
  220. changedPixels[i] = 0; // Set all pixels as up to date.
  221. }
  222. }
  223. #if 0
  224. void SSD1327::writeUpdates(){ // Writes only the pixels that have changed to the display
  225. for (size_t y = 0; y < 128; y++) {
  226. bool continued = false; // If we can continue with the write zone we're using
  227. for (size_t x = 0; x < 128; x++) {
  228. uint16_t address = coordsToAddress(x, y);
  229. if ( bitRead(changedPixels[address/8], address % 8) ) { // If we need an update here
  230. if (!continued) { // Just write the byte, no new write zone needed
  231. continued = true;
  232. setWriteZone(x/2, y, 63, 127); // Set the write zone for this new byte and any subsequent ones
  233. }
  234. writeData(frameBuffer[address]);
  235. bitWrite(changedPixels[address/8], address % 8, 0);
  236. } else {
  237. continued = false; // The chain of pixels is broken
  238. }
  239. }
  240. }
  241. }
  242. void SSD1327::setContrast(uint8_t contrast){
  243. writeCmd(0x81); //set contrast control
  244. writeCmd(contrast); //Contrast byte
  245. }
  246. void SSD1327::initRegs(){ //Sends all the boilerplate startup and config commands to the driver
  247. writeCmd(0xae);//--turn off oled panel
  248. writeCmd(0x15); //set column addresses
  249. writeCmd(0x00); //start column 0
  250. writeCmd(0x7f); //end column 127
  251. writeCmd(0x75); //set row addresses
  252. writeCmd(0x00); //start row 0
  253. writeCmd(0x7f); //end row 127
  254. writeCmd(0x81); //set contrast control
  255. writeCmd(0x80); //50% (128/255)
  256. writeCmd(0xa0); //gment remap
  257. writeCmd(0x51); //51 (To my understanding, this is orientation
  258. writeCmd(0xa1); //start line
  259. writeCmd(0x00);
  260. writeCmd(0xa2); //display offset
  261. writeCmd(0x00);
  262. writeCmd(0xa4); //rmal display
  263. writeCmd(0xa8); //set multiplex ratio
  264. writeCmd(0x7f);
  265. writeCmd(0xb1); //set phase leghth
  266. writeCmd(0xf1);
  267. writeCmd(0xb3); //set dclk
  268. writeCmd(0x00); //80Hz:0xc1 90Hz:0xe1 100Hz:0x00 110Hz:0x30 120Hz:0x50 130Hz:0x70 01
  269. writeCmd(0xab); //Enable vReg
  270. writeCmd(0x01);
  271. writeCmd(0xb6); //set phase leghth
  272. writeCmd(0x0f);
  273. writeCmd(0xbe); //Set vcomh voltage
  274. writeCmd(0x0f);
  275. writeCmd(0xbc); //set pre-charge voltage
  276. writeCmd(0x08);
  277. writeCmd(0xd5); //second precharge period
  278. writeCmd(0x62);
  279. writeCmd(0xfd); //Unlock commands
  280. writeCmd(0x12);
  281. writeCmd(0xAF);
  282. delay(300);
  283. }
  284. void SSD1327::init(){
  285. pinMode(_cs, OUTPUT);
  286. pinMode(_dc, OUTPUT);
  287. pinMode(_rst, OUTPUT);
  288. SPI.setDataMode(SPI_MODE0);
  289. SPI.setBitOrder(MSBFIRST);
  290. SPI.setClockDivider(SPI_CLOCK_DIV2);
  291. SPI.begin();
  292. digitalWrite(_rst, HIGH); //Reset display
  293. delay(100);
  294. digitalWrite(_rst, LOW);
  295. delay(100);
  296. digitalWrite(_rst, HIGH);
  297. delay(100);
  298. initRegs();
  299. }
  300. #endif