Subversion Repositories libSSD1306

Rev

Rev 2 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2 Rev 3
Line 16... Line 16...
16
 All text above, and the splash screen below must be included in any redistribution
16
 All text above, and the splash screen below must be included in any redistribution
17
 
17
 
18
 This code is taken from the ADAfruit library - it is used for playing with an OLED screen
18
 This code is taken from the ADAfruit library - it is used for playing with an OLED screen
19
 
19
 
20
 *********************************************************************/
20
 *********************************************************************/
-
 
21
 
21
#include <stdint.h>
22
#include <stdint.h>
22
#include <string.h>
23
#include <string.h>
23
#include "libSSD1306/SSD1306.h"
24
#include "libSSD1306/SSD1306.h"
24
// pick up gpio settings
-
 
25
#include "main.h"
25
#include "libSSD1306/spiInterface.h"
26
 
-
 
27
 
26
 
28
#define swap(x,y) { typeof(x)t = x; x=y; y=t; }
27
#define swap(x,y) { typeof(x)t = x; x=y; y=t; }
29
#define abs(x)      ((x)>0?(x):-(x))
28
#define abs(x)      ((x)>0?(x):-(x))
30
 
29
 
31
static uint8_t rotation = 0;
30
static uint8_t rotation = 0;
32
const uint16_t WIDTH = SSD1306_LCDWIDTH;
31
const uint16_t WIDTH = SSD1306_LCDWIDTH;
33
const uint16_t HEIGHT = SSD1306_LCDHEIGHT;
32
const uint16_t HEIGHT = SSD1306_LCDHEIGHT;
34
const uint16_t RAMWIDTH = 128;
-
 
35
 
-
 
36
extern SPI_HandleTypeDef hspi1;
-
 
37
 
33
 
38
// the memory buffer for the LCD
34
// the memory buffer for the LCD
39
 
35
 
40
// pointer to the current display - affects buffer used and also chipselect
36
// pointer to the current display - affects buffer used and also chipselect
41
static int cd = 0;
-
 
42
 
-
 
43
uint8_t display_buffer[MAX_PHYS_DISPLAYS][SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH
-
 
44
                / 8];
-
 
45
 
-
 
46
inline uint8_t * display_address(void) {
-
 
47
        return (uint8_t *) (&display_buffer[cd]);
-
 
48
}
-
 
49
 
-
 
50
inline uint8_t getRotation(void) {
-
 
51
        return rotation;
-
 
52
}
-
 
53
 
-
 
54
inline int16_t width(void) {
-
 
55
        switch (rotation) {
-
 
56
        case 0:
-
 
57
                return WIDTH;
-
 
58
                break;
-
 
59
        case 1:
-
 
60
                return WIDTH;
-
 
61
                break;
-
 
62
        case 2:
-
 
63
                return HEIGHT;
-
 
64
                break;
-
 
65
        case 3:
-
 
66
                return -WIDTH;
-
 
67
                break;
-
 
68
        }
-
 
69
        return 0;
-
 
70
}
-
 
71
 
-
 
72
inline int16_t height(void) {
-
 
73
        switch (rotation) {
-
 
74
        case 0:
-
 
75
                return HEIGHT;
-
 
76
                break;
-
 
77
        case 1:
-
 
78
                return HEIGHT;
-
 
79
                break;
-
 
80
        case 2:
-
 
81
                return WIDTH;
-
 
82
                break;
-
 
83
        case 3:
-
 
84
                return -HEIGHT;
-
 
85
                break;
-
 
86
        }
-
 
87
        return 0;
-
 
88
}
-
 
89
 
-
 
90
inline void fastSPIwrite(uint8_t d) {
-
 
91
        uint8_t buffer[1];
-
 
92
        buffer[0] = d;
-
 
93
// todo chipselect based on 'cd' buffer choice
-
 
94
 
-
 
95
#if defined SPI_SPI1
-
 
96
        if(cd==0)
-
 
97
   {
-
 
98
           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_RESET);
-
 
99
   }
-
 
100
#endif
-
 
101
#if defined SPI_SPI2
-
 
102
   if(cd==1)
-
 
103
   {
-
 
104
           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_RESET);
-
 
105
   }
-
 
106
#endif
-
 
107
 
-
 
108
        HAL_SPI_Transmit(&hspi1, buffer, 1, 2);
-
 
109
#if defined SPI_SPI1
-
 
110
           if(cd==0)
-
 
111
           {
-
 
112
                   HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_SET);
-
 
113
           }
-
 
114
#endif
-
 
115
#if defined SPI_SPI2
-
 
116
           if(cd==1)
-
 
117
           {
-
 
118
                   HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
-
 
119
           }
-
 
120
#endif
-
 
121
 
37
 
-
 
38
uint8_t display_buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8];
122
 
39
 
-
 
40
inline uint8_t*
-
 
41
display_address (void)
-
 
42
{
-
 
43
  return (uint8_t*) (&display_buffer[0]);
-
 
44
}
-
 
45
 
-
 
46
inline uint8_t
-
 
47
getRotation (void)
-
 
48
{
-
 
49
  return rotation;
-
 
50
}
-
 
51
 
-
 
52
inline int16_t
-
 
53
width (void)
-
 
54
{
-
 
55
  switch (rotation)
-
 
56
    {
-
 
57
    case 0:
-
 
58
      return WIDTH;
-
 
59
      break;
-
 
60
    case 1:
-
 
61
      return WIDTH;
-
 
62
      break;
-
 
63
    case 2:
-
 
64
      return HEIGHT;
-
 
65
      break;
-
 
66
    case 3:
-
 
67
      return -WIDTH;
-
 
68
      break;
-
 
69
    }
-
 
70
  return 0;
-
 
71
}
-
 
72
 
-
 
73
inline int16_t
-
 
74
height (void)
-
 
75
{
-
 
76
  switch (rotation)
-
 
77
    {
-
 
78
    case 0:
-
 
79
      return HEIGHT;
-
 
80
      break;
-
 
81
    case 1:
-
 
82
      return HEIGHT;
-
 
83
      break;
-
 
84
    case 2:
-
 
85
      return WIDTH;
-
 
86
      break;
-
 
87
    case 3:
-
 
88
      return -HEIGHT;
-
 
89
      break;
-
 
90
    }
-
 
91
  return 0;
123
}
92
}
124
 
93
 
125
// the most basic function, set a single pixel
94
// the most basic function, set a single pixel
126
inline void drawPixel(int16_t x, int16_t y, uint16_t color) {
95
inline void
127
        if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
96
drawPixel (int16_t x, int16_t y, uint16_t color)
128
                return;
97
{
129
 
98
  if ((x < 0) || (x >= width ()) || (y < 0) || (y >= height ()))
130
        // check rotation, move pixel around if necessary
99
    return;
131
        switch (getRotation()) {
100
 
132
        case 1:
101
  // check rotation, move pixel around if necessary
133
                swap(x, y)
102
  switch (getRotation ())
134
                ;
103
    {
135
                x = WIDTH - x - 1;
104
    case 1:
136
                break;
105
      swap(x, y)
137
        case 2:
106
      ;
138
                x = WIDTH - x - 1;
107
      x = WIDTH - x - 1;
139
                y = HEIGHT - y - 1;
108
      break;
140
                break;
109
    case 2:
141
        case 3:
110
      x = WIDTH - x - 1;
142
                swap(x, y)
111
      y = HEIGHT - y - 1;
143
                ;
112
      break;
144
                y = HEIGHT - y - 1;
113
    case 3:
145
                break;
114
      swap(x, y)
146
        }
115
      ;
147
 
116
      y = HEIGHT - y - 1;
148
        // x is which column
117
      break;
149
        switch (color) {
118
    }
150
        case BLACK:
119
 
151
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] &= ~(1 << (y & 7));
120
  // x is which column
152
                break;
121
  switch (color)
153
 
122
    {
154
        default:
123
    case BLACK:
155
        case WHITE:
124
      display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] &= ~(1 << (y & 7));
156
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
125
      break;
157
                break;
126
 
158
 
127
    default:
159
        case INVERT:
128
    case WHITE:
160
                display_buffer[cd][x + (y / 8) * SSD1306_LCDWIDTH] ^= (1 << (y & 7));
129
      display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] |= (1 << (y & 7));
161
                break;
130
      break;
162
        }
131
 
163
}
132
    case INVERT:
164
 
133
      display_buffer[x + (y / 8) * SSD1306_LCDWIDTH] ^= (1 << (y & 7));
165
void ssd1306_begin(uint8_t vccstate, uint8_t i2caddr) {
134
      break;
166
 
135
    }
167
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_SET);
136
}
168
 
137
 
169
        // VDD (3.3V) goes high at start, lets just chill for a ms
138
void
170
        HAL_Delay(1);
139
ssd1306_begin (uint8_t vccstate, uint8_t i2caddr)
171
        // bring reset low
140
{
172
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_RESET);
141
 
173
        // wait 10ms
142
  (void) i2caddr;
174
        HAL_Delay(10);
143
  ssd1306resetDisplay ();
175
        // bring out of reset
144
 
176
        HAL_GPIO_WritePin(SPI_RESET_GPIO_Port, SPI_RESET_Pin, GPIO_PIN_SET);
145
  // Init sequence for 128x32 or 128x64  OLED module
177
        // turn on VCC (9V?)
146
  ssd1306commandSPIwrite (SSD1306_DISPLAYOFF); // 0xAE
178
 
147
  ssd1306commandSPIwrite (SSD1306_SETDISPLAYCLOCKDIV); // 0xD5
179
        for (cd = 0; cd < 2; cd++) {
148
  ssd1306commandSPIwrite (0x80); // the suggested ratio 0x80
180
                select_display(cd);
149
  ssd1306commandSPIwrite (SSD1306_SETMULTIPLEX); // 0xA8
181
#if defined SSD1306_128_32
150
  ssd1306commandSPIwrite (SSD1306_LCDHEIGHT - 1);
182
                // Init sequence for 128x32 OLED module
151
  ssd1306commandSPIwrite (SSD1306_SETDISPLAYOFFSET); // 0xD3
183
                ssd1306_command(SSD1306_DISPLAYOFF);// 0xAE
152
  ssd1306commandSPIwrite (0x0); // no offset
184
                ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);// 0xD5
153
  ssd1306commandSPIwrite (SSD1306_SETSTARTLINE | 0x0); // line #0
185
                ssd1306_command(0x80);// the suggested ratio 0x80
154
  ssd1306commandSPIwrite (SSD1306_CHARGEPUMP); // 0x8D
186
                ssd1306_command(SSD1306_SETMULTIPLEX);// 0xA8
155
  if (vccstate == SSD1306_EXTERNALVCC)
187
                ssd1306_command(0x1F);
156
    {
188
                ssd1306_command(SSD1306_SETDISPLAYOFFSET);// 0xD3
157
      ssd1306commandSPIwrite (0x10);
189
                ssd1306_command(0x0);// no offset
158
    }
190
                ssd1306_command(SSD1306_SETSTARTLINE | 0x0);// line #0
159
  else
191
                ssd1306_command(SSD1306_CHARGEPUMP);// 0x8D
160
    {
192
                if (vccstate == SSD1306_EXTERNALVCC)
161
      ssd1306commandSPIwrite (0x14);
193
                {       ssd1306_command(0x10);}
162
    }
194
                else
163
  ssd1306commandSPIwrite (SSD1306_MEMORYMODE);                    // 0x20
195
                {       ssd1306_command(0x14);}
164
  ssd1306commandSPIwrite (0x00);                    // 0x0 act like ks0108
196
                ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
165
  ssd1306commandSPIwrite (SSD1306_SEGREMAP | 0x1);
197
                ssd1306_command(0x00);// 0x0 act like ks0108
166
  ssd1306commandSPIwrite (SSD1306_COMSCANDEC);
198
                ssd1306_command(SSD1306_SEGREMAP | 0x1);
167
  ssd1306commandSPIwrite (SSD1306_SETCOMPINS);                    // 0xDA
199
                ssd1306_command(SSD1306_COMSCANDEC);
168
  ssd1306commandSPIwrite (SSD1306_LCDHEIGHT == 32 ? 0x02 : 0x12);
200
                ssd1306_command(SSD1306_SETCOMPINS);// 0xDA
169
  ssd1306commandSPIwrite (SSD1306_SETCONTRAST);                    // 0x81
201
                ssd1306_command(0x02);
170
  if (vccstate == SSD1306_EXTERNALVCC)
202
                ssd1306_command(SSD1306_SETCONTRAST);// 0x81
171
    {
203
                ssd1306_command(0x8F);
172
      ssd1306commandSPIwrite (0x9F);
204
                ssd1306_command(SSD1306_SETPRECHARGE);// 0xd9
173
    }
205
                if (vccstate == SSD1306_EXTERNALVCC)
174
  else
206
                {       ssd1306_command(0x22);}
175
    {
207
                else
176
      ssd1306commandSPIwrite (0xCF);
208
                {       ssd1306_command(0xF1);}
177
    }
209
                ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
178
  ssd1306commandSPIwrite (SSD1306_SETPRECHARGE);                    // 0xd9
210
                ssd1306_command(0x40);
179
  if (vccstate == SSD1306_EXTERNALVCC)
211
                ssd1306_command(SSD1306_DISPLAYALLON_RESUME);// 0xA4
180
    {
212
                ssd1306_command(SSD1306_NORMALDISPLAY);// 0xA6
181
      ssd1306commandSPIwrite (0x22);
213
#endif
182
    }
214
 
183
  else
215
#if defined SSD1306_128_64
184
    {
216
                // Init sequence for 128x64 OLED module
185
      ssd1306commandSPIwrite (0xF1);
217
                ssd1306_command(SSD1306_DISPLAYOFF);                    // 0xAE
186
    }
218
                ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV);            // 0xD5
187
  ssd1306commandSPIwrite (SSD1306_SETVCOMDETECT);                 // 0xDB
219
                ssd1306_command(0x80);                       // the suggested ratio 0x80
188
  ssd1306commandSPIwrite (0x40);
220
                ssd1306_command(SSD1306_SETMULTIPLEX);                  // 0xA8
189
  ssd1306commandSPIwrite (SSD1306_DISPLAYALLON_RESUME);                 // 0xA4
221
                ssd1306_command(0x3F);
190
  ssd1306commandSPIwrite (SSD1306_NORMALDISPLAY);                 // 0xA6
222
                ssd1306_command(SSD1306_SETDISPLAYOFFSET);              // 0xD3
191
 
223
                ssd1306_command(0x0);                                   // no offset
192
  ssd1306commandSPIwrite (SSD1306_DISPLAYON);             //--turn on oled panel
224
                ssd1306_command(SSD1306_SETSTARTLINE | 0x0);            // line #0
193
 
225
                ssd1306_command(SSD1306_CHARGEPUMP);                    // 0x8D
194
}
226
                if (vccstate == SSD1306_EXTERNALVCC) {
195
 
227
                        ssd1306_command(0x10);
196
void
228
                } else {
197
invertDisplay (uint8_t i)
229
                        ssd1306_command(0x14);
198
{
230
                }
199
  if (i)
231
                ssd1306_command(SSD1306_MEMORYMODE);                    // 0x20
200
    {
232
                ssd1306_command(0x00);                            // 0x0 act like ks0108
201
      ssd1306commandSPIwrite (SSD1306_INVERTDISPLAY);
233
                ssd1306_command(SSD1306_SEGREMAP | 0x1);
202
    }
234
                ssd1306_command(SSD1306_COMSCANDEC);
203
  else
235
                ssd1306_command(SSD1306_SETCOMPINS);                    // 0xDA
204
    {
236
                ssd1306_command(0x12);
205
      ssd1306commandSPIwrite (SSD1306_NORMALDISPLAY);
237
                ssd1306_command(SSD1306_SETCONTRAST);                   // 0x81
206
    }
238
                if (vccstate == SSD1306_EXTERNALVCC) {
-
 
239
                        ssd1306_command(0x9F);
-
 
240
                } else {
-
 
241
                        ssd1306_command(0xCF);
-
 
242
                }
-
 
243
                ssd1306_command(SSD1306_SETPRECHARGE);                  // 0xd9
-
 
244
                if (vccstate == SSD1306_EXTERNALVCC) {
-
 
245
                        ssd1306_command(0x22);
-
 
246
                } else {
-
 
247
                        ssd1306_command(0xF1);
-
 
248
                }
-
 
249
                ssd1306_command(SSD1306_SETVCOMDETECT);                 // 0xDB
-
 
250
                ssd1306_command(0x40);
-
 
251
                ssd1306_command(SSD1306_DISPLAYALLON_RESUME);           // 0xA4
-
 
252
                ssd1306_command(SSD1306_NORMALDISPLAY);                 // 0xA6
-
 
253
#endif
-
 
254
 
-
 
255
                ssd1306_command(SSD1306_DISPLAYON);               //--turn on oled panel
-
 
256
        }
-
 
257
        select_display(0);
-
 
258
}
-
 
259
 
-
 
260
void invertDisplay(uint8_t i) {
-
 
261
        if (i) {
-
 
262
                ssd1306_command(SSD1306_INVERTDISPLAY);
-
 
263
        } else {
-
 
264
                ssd1306_command(SSD1306_NORMALDISPLAY);
-
 
265
        }
-
 
266
}
-
 
267
 
-
 
268
void ssd1306_command(uint8_t c) {
-
 
269
        HAL_GPIO_WritePin(SPI_CD_GPIO_Port, SPI_CD_Pin, GPIO_PIN_RESET);
-
 
270
 
-
 
271
        fastSPIwrite(c);
-
 
272
 
-
 
273
}
207
}
274
 
208
 
275
// startscrollright
209
// startscrollright
276
// Activate a right handed scroll for rows start through stop
210
// Activate a right handed scroll for rows start through stop
277
// Hint, the display is 16 rows tall. To scroll the whole display, run:
211
// Hint, the display is 16 rows tall. To scroll the whole display, run:
278
// display.scrollright(0x00, 0x0F) 
212
// display.scrollright(0x00, 0x0F) 
-
 
213
void
279
void startscrollright(uint8_t start, uint8_t stop) {
214
startscrollright (uint8_t start, uint8_t stop)
-
 
215
{
280
        ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL);
216
  ssd1306commandSPIwrite (SSD1306_RIGHT_HORIZONTAL_SCROLL);
281
        ssd1306_command(0X00);
217
  ssd1306commandSPIwrite (0X00);
282
        ssd1306_command(start);
218
  ssd1306commandSPIwrite (start);
283
        ssd1306_command(0X00);
219
  ssd1306commandSPIwrite (0X00);
284
        ssd1306_command(stop);
220
  ssd1306commandSPIwrite (stop);
285
        ssd1306_command(0X00);
221
  ssd1306commandSPIwrite (0X00);
286
        ssd1306_command(0XFF);
222
  ssd1306commandSPIwrite (0XFF);
287
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
223
  ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
288
}
224
}
289
 
225
 
290
// startscrollleft
226
// startscrollleft
291
// Activate a right handed scroll for rows start through stop
227
// Activate a right handed scroll for rows start through stop
292
// Hint, the display is 16 rows tall. To scroll the whole display, run:
228
// Hint, the display is 16 rows tall. To scroll the whole display, run:
293
// display.scrollright(0x00, 0x0F) 
229
// display.scrollright(0x00, 0x0F) 
-
 
230
void
294
void startscrollleft(uint8_t start, uint8_t stop) {
231
startscrollleft (uint8_t start, uint8_t stop)
-
 
232
{
295
        ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL);
233
  ssd1306commandSPIwrite (SSD1306_LEFT_HORIZONTAL_SCROLL);
296
        ssd1306_command(0X00);
234
  ssd1306commandSPIwrite (0X00);
297
        ssd1306_command(start);
235
  ssd1306commandSPIwrite (start);
298
        ssd1306_command(0X00);
236
  ssd1306commandSPIwrite (0X00);
299
        ssd1306_command(stop);
237
  ssd1306commandSPIwrite (stop);
300
        ssd1306_command(0X00);
238
  ssd1306commandSPIwrite (0X00);
301
        ssd1306_command(0XFF);
239
  ssd1306commandSPIwrite (0XFF);
302
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
240
  ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
303
}
241
}
304
 
242
 
305
// startscrolldiagright
243
// startscrolldiagright
306
// Activate a diagonal scroll for rows start through stop
244
// Activate a diagonal scroll for rows start through stop
307
// Hint, the display is 16 rows tall. To scroll the whole display, run:
245
// Hint, the display is 16 rows tall. To scroll the whole display, run:
308
// display.scrollright(0x00, 0x0F) 
246
// display.scrollright(0x00, 0x0F) 
-
 
247
void
309
void startscrolldiagright(uint8_t start, uint8_t stop) {
248
startscrolldiagright (uint8_t start, uint8_t stop)
-
 
249
{
310
        ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
250
  ssd1306commandSPIwrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
311
        ssd1306_command(0X00);
251
  ssd1306commandSPIwrite (0X00);
312
        ssd1306_command(SSD1306_LCDHEIGHT);
252
  ssd1306commandSPIwrite (SSD1306_LCDHEIGHT);
313
        ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
253
  ssd1306commandSPIwrite (SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL);
314
        ssd1306_command(0X00);
254
  ssd1306commandSPIwrite (0X00);
315
        ssd1306_command(start);
255
  ssd1306commandSPIwrite (start);
316
        ssd1306_command(0X00);
256
  ssd1306commandSPIwrite (0X00);
317
        ssd1306_command(stop);
257
  ssd1306commandSPIwrite (stop);
318
        ssd1306_command(0X01);
258
  ssd1306commandSPIwrite (0X01);
319
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
259
  ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
320
}
260
}
321
 
261
 
322
// startscrolldiagleft
262
// startscrolldiagleft
323
// Activate a diagonal scroll for rows start through stop
263
// Activate a diagonal scroll for rows start through stop
324
// Hint, the display is 16 rows tall. To scroll the whole display, run:
264
// Hint, the display is 16 rows tall. To scroll the whole display, run:
325
// display.scrollright(0x00, 0x0F) 
265
// display.scrollright(0x00, 0x0F) 
-
 
266
void
326
void startscrolldiagleft(uint8_t start, uint8_t stop) {
267
startscrolldiagleft (uint8_t start, uint8_t stop)
-
 
268
{
327
        ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA);
269
  ssd1306commandSPIwrite (SSD1306_SET_VERTICAL_SCROLL_AREA);
328
        ssd1306_command(0X00);
270
  ssd1306commandSPIwrite (0X00);
329
        ssd1306_command(SSD1306_LCDHEIGHT);
271
  ssd1306commandSPIwrite (SSD1306_LCDHEIGHT);
330
        ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
272
  ssd1306commandSPIwrite (SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL);
331
        ssd1306_command(0X00);
273
  ssd1306commandSPIwrite (0X00);
332
        ssd1306_command(start);
274
  ssd1306commandSPIwrite (start);
333
        ssd1306_command(0X00);
275
  ssd1306commandSPIwrite (0X00);
334
        ssd1306_command(stop);
276
  ssd1306commandSPIwrite (stop);
335
        ssd1306_command(0X01);
277
  ssd1306commandSPIwrite (0X01);
336
        ssd1306_command(SSD1306_ACTIVATE_SCROLL);
278
  ssd1306commandSPIwrite (SSD1306_ACTIVATE_SCROLL);
337
}
279
}
338
 
280
 
-
 
281
void
339
void stopscroll(void) {
282
stopscroll (void)
-
 
283
{
340
        ssd1306_command(SSD1306_DEACTIVATE_SCROLL);
284
  ssd1306commandSPIwrite (SSD1306_DEACTIVATE_SCROLL);
341
}
285
}
342
 
286
 
343
// Dim the display
287
// Dim the display
344
// dim = true: display is dimmed
288
// dim = true: display is dimmed
345
// dim = false: display is normal
289
// dim = false: display is normal
346
void dim(uint8_t dim) {
290
void
347
        uint8_t contrast;
291
dim (uint8_t contrast)
348
 
292
{
349
        if (dim) {
-
 
350
                contrast = 0; // Dimmed display
-
 
351
        } else {
-
 
352
                contrast = 0xCF;
-
 
353
        }
293
 
354
        // the range of contrast to too small to be really useful
294
  // the range of contrast to too small to be really useful
355
        // it is useful to dim the display
295
  // it is useful to dim the display
356
        ssd1306_command(SSD1306_SETCONTRAST);
296
  ssd1306commandSPIwrite (SSD1306_SETCONTRAST);
357
        ssd1306_command(contrast);
297
  ssd1306commandSPIwrite (contrast);
358
}
298
}
359
 
299
 
-
 
300
void
360
void display(void) {
301
display (void)
-
 
302
{
-
 
303
 
-
 
304
  // select entire display as window to write into
361
        ssd1306_command(SSD1306_COLUMNADDR);
305
  ssd1306commandSPIwrite (SSD1306_COLUMNADDR);
362
        ssd1306_command(0);   // Column start address (0 = reset)
306
  ssd1306commandSPIwrite (0);   // Column start address (0 = reset)
363
        ssd1306_command(RAMWIDTH-1); // Column end address (127 = reset)
307
  ssd1306commandSPIwrite (SSD1306_RAMWIDTH - 1); // Column end address (127 = reset)
364
 
308
 
365
        ssd1306_command(SSD1306_PAGEADDR);
309
  ssd1306commandSPIwrite (SSD1306_PAGEADDR);
366
        ssd1306_command(0); // Page start address (0 = reset)
310
  ssd1306commandSPIwrite (0); // Page start address (0 = reset)
367
        ssd1306_command((SSD1306_LCDHEIGHT == 64) ? 7 : 3); // Page end address
311
  ssd1306commandSPIwrite ((SSD1306_LCDHEIGHT == 64) ? 7 : 3); // Page end address
368
 
312
 
369
        int row;
313
  int row;
-
 
314
 
370
        int col = 2;
315
  int col = SSD1306_RAMWIDTH == 132 ? 2 : 0;
371
        for (row = 0; row < SSD1306_LCDHEIGHT / 8; row++) {
316
  for (row = 0; row < SSD1306_LCDHEIGHT / 8; row++)
-
 
317
    {
372
                // set the cursor to
318
      // set the cursor to
373
                ssd1306_command(0xB0 + row); //set page address
319
      ssd1306commandSPIwrite (0xB0 + row); //set page address
374
                ssd1306_command(col & 0xf); //set lower column address
320
      ssd1306commandSPIwrite (col & 0xf); //set lower column address
375
                ssd1306_command(0x10 | (col >> 4)); //set higher column address
321
      ssd1306commandSPIwrite (0x10 | (col >> 4)); //set higher column address
376
 
-
 
377
 
-
 
378
                HAL_GPIO_WritePin(SPI_CD_GPIO_Port, SPI_CD_Pin, GPIO_PIN_SET);
-
 
379
 
322
 
380
#if defined SPI_SPI1
323
      ssd1306SendDisplay (
381
                 if(cd==0)
-
 
382
                   {
-
 
383
                           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_RESET);
324
          (uint8_t*) (&display_buffer[0]) + row * SSD1306_LCDWIDTH,
384
                   }
-
 
385
#endif
-
 
386
#if defined SPI_SPI2
325
          SSD1306_LCDWIDTH);
387
                   if(cd==1)
-
 
388
                   {
-
 
389
                           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_RESET);
-
 
390
                   }
-
 
391
#endif
-
 
392
 
326
 
393
 
-
 
394
 
-
 
395
                HAL_SPI_Transmit(&hspi1,
-
 
396
                                (uint8_t *) (&display_buffer[cd]) + row * SSD1306_LCDWIDTH,
-
 
397
                                SSD1306_LCDWIDTH, 100);
-
 
398
#if defined SPI_SPI1
-
 
399
                   if(cd==0)
-
 
400
                   {
-
 
401
                           HAL_GPIO_WritePin(SPI_NSS1_GPIO_Port, SPI_NSS1_Pin, GPIO_PIN_SET);
-
 
402
                   }
327
    }
403
#endif
-
 
404
#if defined SPI_SPI2
-
 
405
 
-
 
406
                   if(cd==1)
-
 
407
                   {
-
 
408
                           HAL_GPIO_WritePin(SPI_NSS2_GPIO_Port, SPI_NSS2_Pin, GPIO_PIN_SET);
-
 
409
                   }
-
 
410
#endif
-
 
411
                   HAL_GPIO_WritePin(SPI_CD_GPIO_Port, SPI_CD_Pin, GPIO_PIN_RESET);
-
 
412
 
-
 
413
        }
-
 
414
 
328
 
415
}
329
}
416
 
330
 
417
// clear everything
331
// clear everything
418
void clearDisplay(void) {
-
 
419
        memset(&display_buffer[cd], 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
-
 
420
}
-
 
421
 
-
 
422
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
-
 
423
        boolean bSwap = false;
-
 
424
        switch (rotation) {
-
 
425
        case 0:
-
 
426
                // 0 degree rotation, do nothing
-
 
427
                break;
-
 
428
        case 1:
-
 
429
                // 90 degree rotation, swap x & y for rotation, then invert x
-
 
430
                bSwap = true;
-
 
431
                swap(x, y)
-
 
432
                ;
-
 
433
                x = WIDTH - x - 1;
-
 
434
                break;
-
 
435
        case 2:
-
 
436
                // 180 degree rotation, invert x and y - then shift y around for height.
-
 
437
                x = WIDTH - x - 1;
-
 
438
                y = HEIGHT - y - 1;
-
 
439
                x -= (w - 1);
-
 
440
                break;
-
 
441
        case 3:
-
 
442
                // 270 degree rotation, swap x & y for rotation, then invert y  and adjust y for w (not to become h)
-
 
443
                bSwap = true;
-
 
444
                swap(x, y)
-
 
445
                ;
-
 
446
                y = HEIGHT - y - 1;
-
 
447
                y -= (w - 1);
-
 
448
                break;
-
 
449
        }
-
 
450
 
-
 
451
        if (bSwap) {
-
 
452
                drawFastVLineInternal(x, y, w, color);
-
 
453
        } else {
-
 
454
                drawFastHLineInternal(x, y, w, color);
-
 
455
        }
-
 
456
}
-
 
457
 
-
 
458
void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) {
-
 
459
        // Do bounds/limit checks
-
 
460
        if (y < 0 || y >= HEIGHT) {
-
 
461
                return;
-
 
462
        }
-
 
463
 
-
 
464
        // make sure we don't try to draw below 0
-
 
465
        if (x < 0) {
-
 
466
                w += x;
-
 
467
                x = 0;
-
 
468
        }
-
 
469
 
-
 
470
        // make sure we don't go off the edge of the display
-
 
471
        if ((x + w) > WIDTH) {
-
 
472
                w = (HEIGHT - x);
-
 
473
        }
-
 
474
 
-
 
475
        // if our width is now negative, punt
-
 
476
        if (w <= 0) {
-
 
477
                return;
-
 
478
        }
-
 
479
 
-
 
480
        // set up the pointer for  movement through the buffer
-
 
481
        register uint8_t *pBuf = display_address();
-
 
482
        // adjust the buffer pointer for the current row
-
 
483
        pBuf += ((y / 8) * SSD1306_LCDWIDTH);
-
 
484
        // and offset x columns in
-
 
485
        pBuf += x;
-
 
486
 
-
 
487
        register uint8_t mask = 1 << (y & 7);
-
 
488
 
-
 
489
        if (color == WHITE) {
-
 
490
                while (w--) {
-
 
491
                        *pBuf++ |= mask;
-
 
492
                }
-
 
493
        } else {
-
 
494
                mask = ~mask;
-
 
495
                while (w--) {
-
 
496
                        *pBuf++ &= mask;
-
 
497
                }
332
void
498
        }
-
 
499
}
-
 
500
 
-
 
501
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
-
 
502
        boolean bSwap = false;
333
clearDisplay (void)
503
        switch (rotation) {
-
 
504
        case 0:
-
 
505
                break;
-
 
506
        case 1:
-
 
507
                // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w)
-
 
508
                bSwap = true;
-
 
509
                swap(x, y)
-
 
510
                ;
-
 
511
                x = WIDTH - x - 1;
-
 
512
                x -= (h - 1);
-
 
513
                break;
-
 
514
        case 2:
-
 
515
                // 180 degree rotation, invert x and y - then shift y around for height.
-
 
516
                x = WIDTH - x - 1;
-
 
517
                y = HEIGHT - y - 1;
-
 
518
                y -= (h - 1);
-
 
519
                break;
-
 
520
        case 3:
-
 
521
                // 270 degree rotation, swap x & y for rotation, then invert y
-
 
522
                bSwap = true;
-
 
523
                swap(x, y)
-
 
524
                ;
-
 
525
                y = HEIGHT - y - 1;
-
 
526
                break;
-
 
527
        }
-
 
528
 
-
 
529
        if (bSwap) {
-
 
530
                drawFastHLineInternal(x, y, h, color);
-
 
531
        } else {
-
 
532
                drawFastVLineInternal(x, y, h, color);
-
 
533
        }
-
 
534
}
334
{
535
 
-
 
536
void drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) {
-
 
537
 
-
 
538
        // do nothing if we're off the left or right side of the screen
-
 
539
        if (x < 0 || x >= WIDTH) {
-
 
540
                return;
-
 
541
        }
-
 
542
 
-
 
543
        // make sure we don't try to draw below 0
-
 
544
        if (__y < 0) {
-
 
545
                // __y is negative, this will subtract enough from __h to account for __y being 0
-
 
546
                __h += __y;
-
 
547
                __y = 0;
-
 
548
 
-
 
549
        }
-
 
550
 
-
 
551
        // make sure we don't go past the height of the display
-
 
552
        if ((__y + __h) > HEIGHT) {
-
 
553
                __h = (HEIGHT - __y);
-
 
554
        }
-
 
555
 
-
 
556
        // if our height is now negative, punt
-
 
557
        if (__h <= 0) {
-
 
558
                return;
-
 
559
        }
-
 
560
 
-
 
561
        // this display doesn't need ints for coordinates, use local byte registers for faster juggling
-
 
562
        register uint8_t y = __y;
-
 
563
        register uint8_t h = __h;
-
 
564
 
-
 
565
        // set up the pointer for fast movement through the buffer
-
 
566
        register uint8_t *pBuf = display_address();
-
 
567
        // adjust the buffer pointer for the current row
-
 
568
        pBuf += ((y / 8) * SSD1306_LCDWIDTH);
335
  memset (&display_buffer, 0, (SSD1306_LCDWIDTH * SSD1306_LCDHEIGHT / 8));
569
        // and offset x columns in
-
 
570
        pBuf += x;
-
 
571
 
-
 
572
        // do the first partial byte, if necessary - this requires some masking
-
 
573
        register uint8_t mod = (y & 7);
-
 
574
        if (mod) {
-
 
575
                // mask off the high n bits we want to set
-
 
576
                mod = 8 - mod;
-
 
577
 
-
 
578
                // note - lookup table results in a nearly 10% performance improvement in fill* functions
-
 
579
                // register uint8_t mask = ~(0xFF >> (mod));
-
 
580
                static uint8_t premask[8] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC,
-
 
581
                                0xFE };
-
 
582
                register uint8_t mask = premask[mod];
-
 
583
 
-
 
584
                // adjust the mask if we're not going to reach the end of this byte
-
 
585
                if (h < mod) {
-
 
586
                        mask &= (0XFF >> (mod - h));
-
 
587
                }
-
 
588
 
-
 
589
                if (color == WHITE) {
-
 
590
                        *pBuf |= mask;
-
 
591
                } else {
-
 
592
                        *pBuf &= ~mask;
-
 
593
                }
-
 
594
 
-
 
595
                // fast exit if we're done here!
-
 
596
                if (h < mod) {
-
 
597
                        return;
-
 
598
                }
-
 
599
 
-
 
600
                h -= mod;
-
 
601
 
-
 
602
                pBuf += SSD1306_LCDWIDTH;
-
 
603
        }
-
 
604
 
-
 
605
        // write solid bytes while we can - effectively doing 8 rows at a time
-
 
606
        if (h >= 8) {
-
 
607
                // store a local value to work with
-
 
608
                register uint8_t val = (color == WHITE) ? 255 : 0;
-
 
609
 
-
 
610
                do {
-
 
611
                        // write our value in
-
 
612
                        *pBuf = val;
-
 
613
 
-
 
614
                        // adjust the buffer forward 8 rows worth of data
-
 
615
                        pBuf += SSD1306_LCDWIDTH;
-
 
616
 
-
 
617
                        // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now)
-
 
618
                        h -= 8;
-
 
619
                } while (h >= 8);
-
 
620
        }
-
 
621
 
-
 
622
        // now do the final partial byte, if necessary
-
 
623
        if (h) {
-
 
624
                mod = h & 7;
-
 
625
                // this time we want to mask the low bits of the byte, vs the high bits we did above
-
 
626
                // register uint8_t mask = (1 << mod) - 1;
-
 
627
                // note - lookup table results in a nearly 10% performance improvement in fill* functions
-
 
628
                static uint8_t postmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,
-
 
629
                                0x7F };
-
 
630
                register uint8_t mask = postmask[mod];
-
 
631
                if (color == WHITE) {
-
 
632
                        *pBuf |= mask;
-
 
633
                } else {
-
 
634
                        *pBuf &= ~mask;
-
 
635
                }
-
 
636
        }
-
 
637
}
336
}
638
 
337
 
639
/* using Bresenham draw algorithm */
338
/* using Bresenham draw algorithm */
-
 
339
void
640
void drawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color) {
340
drawLine (int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint8_t color)
-
 
341
{
641
        int16_t x, y, dx,               //deltas
342
  int16_t x, y, dx, dy,    //deltas
642
                        dy, dx2,        //scaled deltas
343
      dx2, dy2, //scaled deltas
643
                        dy2, ix,                //increase rate on the x axis
344
      ix, iy,   //increase rate on the x and y axis
644
                        iy,             //increase rate on the y axis
-
 
645
                        err;    //the error term
345
      err;      //the error term
646
        uint16_t i;             //looping variable
346
  uint16_t i;           //looping variable
647
 
347
 
648
        // identify the first pixel
348
  // identify the first pixel
649
        x = x1;
349
  x = x1;
650
        y = y1;
350
  y = y1;
651
 
351
 
652
        // difference between starting and ending points
352
  // difference between starting and ending points
653
        dx = x2 - x1;
353
  dx = x2 - x1;
654
        dy = y2 - y1;
354
  dy = y2 - y1;
655
 
355
 
656
        // calculate direction of the vector and store in ix and iy
356
  // calculate direction of the vector and store in ix and iy
657
        if (dx >= 0)
357
  if (dx >= 0)
658
                ix = 1;
358
    ix = 1;
659
 
359
 
660
        if (dx < 0) {
360
  if (dx < 0)
-
 
361
    {
661
                ix = -1;
362
      ix = -1;
662
                dx = abs(dx);
363
      dx = abs(dx);
663
        }
364
    }
664
 
365
 
665
        if (dy >= 0)
366
  if (dy >= 0)
666
                iy = 1;
367
    iy = 1;
667
 
368
 
668
        if (dy < 0) {
369
  if (dy < 0)
-
 
370
    {
669
                iy = -1;
371
      iy = -1;
670
                dy = abs(dy);
372
      dy = abs(dy);
671
        }
373
    }
672
 
374
 
673
        // scale deltas and store in dx2 and dy2
375
  // scale deltas and store in dx2 and dy2
674
        dx2 = dx * 2;
376
  dx2 = dx * 2;
675
        dy2 = dy * 2;
377
  dy2 = dy * 2;
676
 
378
 
677
// all  variables are set and it's time to enter the main loop.
379
// all  variables are set and it's time to enter the main loop.
678
 
380
 
679
        if (dx > dy)    // dx is the major axis
381
  if (dx > dy)  // dx is the major axis
680
                        {
382
    {
681
                // initialize the error term
383
      // initialize the error term
682
                err = dy2 - dx;
384
      err = dy2 - dx;
683
 
-
 
684
                for (i = 0; i <= dx; i++) {
-
 
685
                        drawPixel(x, y, color);
-
 
686
                        if (err >= 0) {
-
 
687
                                err -= dx2;
-
 
688
                                y += iy;
-
 
689
                        }
-
 
690
                        err += dy2;
-
 
691
                        x += ix;
-
 
692
                }
-
 
693
        }
-
 
694
 
385
 
695
        else            // dy is the major axis
386
      for (i = 0; i <= dx; i++)
696
        {
387
        {
-
 
388
          drawPixel (x, y, color);
-
 
389
          if (err >= 0)
-
 
390
            {
-
 
391
              err -= dx2;
-
 
392
              y += iy;
-
 
393
            }
-
 
394
          err += dy2;
-
 
395
          x += ix;
-
 
396
        }
-
 
397
    }
-
 
398
 
-
 
399
  else          // dy is the major axis
-
 
400
    {
697
                // initialize the error term
401
      // initialize the error term
698
                err = dx2 - dy;
402
      err = dx2 - dy;
699
 
403
 
700
                for (i = 0; i <= dy; i++) {
404
      for (i = 0; i <= dy; i++)
-
 
405
        {
701
                        drawPixel(x, y, color);
406
          drawPixel (x, y, color);
702
                        if (err >= 0) {
407
          if (err >= 0)
-
 
408
            {
703
                                err -= dy2;
409
              err -= dy2;
704
                                x += ix;
410
              x += ix;
705
                        }
411
            }
706
                        err += dx2;
412
          err += dx2;
707
                        y += iy;
413
          y += iy;
708
                }
-
 
709
        }
-
 
710
}
-
 
711
 
-
 
712
void select_display(int i) {
-
 
713
        if (i < MAX_PHYS_DISPLAYS) {
-
 
714
                cd = i;
-
 
715
        }
414
        }
-
 
415
    }
716
}
416
}