SSD1327.cpp 9.9 KB

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