SSD1327.cpp 9.8 KB

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