Frank Duignan
/
NRF52832_ili9341
Basic driver working
display.cpp@81:7087ba9d18bb, 2021-02-20 (annotated)
- Committer:
- f3d
- Date:
- Sat Feb 20 16:34:49 2021 +0000
- Revision:
- 81:7087ba9d18bb
- Parent:
- 80:ff42f77928ad
Display driver working with touch input
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
f3d | 80:ff42f77928ad | 1 | #include "mbed.h" |
f3d | 80:ff42f77928ad | 2 | #include "display.h" |
f3d | 81:7087ba9d18bb | 3 | #include "font5x7.h" |
f3d | 81:7087ba9d18bb | 4 | extern Serial g_Serial_pc; |
f3d | 80:ff42f77928ad | 5 | //mosi,miso,clk,ss |
f3d | 81:7087ba9d18bb | 6 | SPI spi(P0_25,P0_26,P0_27); |
f3d | 80:ff42f77928ad | 7 | DigitalOut Rst(P0_7); |
f3d | 80:ff42f77928ad | 8 | DigitalOut DC(P0_6); |
f3d | 81:7087ba9d18bb | 9 | DigitalOut D_CS(P0_28); |
f3d | 81:7087ba9d18bb | 10 | DigitalOut T_CS(P0_5); |
f3d | 81:7087ba9d18bb | 11 | DigitalIn PenIRQ(P0_4); |
f3d | 80:ff42f77928ad | 12 | void Display::begin() |
f3d | 80:ff42f77928ad | 13 | { |
f3d | 81:7087ba9d18bb | 14 | |
f3d | 80:ff42f77928ad | 15 | spi.format(8, 0); |
f3d | 80:ff42f77928ad | 16 | spi.frequency(8000000); |
f3d | 81:7087ba9d18bb | 17 | T_CS = 1; // de-assert the touch interface for now |
f3d | 81:7087ba9d18bb | 18 | D_CS = 1; |
f3d | 81:7087ba9d18bb | 19 | |
f3d | 80:ff42f77928ad | 20 | resetDisplay(); |
f3d | 81:7087ba9d18bb | 21 | |
f3d | 81:7087ba9d18bb | 22 | LCD_Write_Data(0x21); // Set GVDD (varies contrast) |
f3d | 81:7087ba9d18bb | 23 | |
f3d | 80:ff42f77928ad | 24 | LCD_Write_Cmd(0xC0); // Power control |
f3d | 80:ff42f77928ad | 25 | LCD_Write_Data(0x21); // Set GVDD (varies contrast) |
f3d | 80:ff42f77928ad | 26 | |
f3d | 80:ff42f77928ad | 27 | LCD_Write_Cmd(0xC1); // Power control |
f3d | 80:ff42f77928ad | 28 | LCD_Write_Data(0x10); // default value |
f3d | 80:ff42f77928ad | 29 | |
f3d | 80:ff42f77928ad | 30 | LCD_Write_Cmd(0xC5); //VCM control |
f3d | 80:ff42f77928ad | 31 | LCD_Write_Data(0x31); // default values |
f3d | 80:ff42f77928ad | 32 | LCD_Write_Data(0x3c); // |
f3d | 80:ff42f77928ad | 33 | |
f3d | 80:ff42f77928ad | 34 | LCD_Write_Cmd(0xC7); //VCM control2 |
f3d | 80:ff42f77928ad | 35 | LCD_Write_Data(0xc0); // default value |
f3d | 80:ff42f77928ad | 36 | |
f3d | 80:ff42f77928ad | 37 | LCD_Write_Cmd(0x36); // Memory Access Control |
f3d | 80:ff42f77928ad | 38 | LCD_Write_Data(0x48); // Set display orientation and RGB colour order |
f3d | 80:ff42f77928ad | 39 | |
f3d | 80:ff42f77928ad | 40 | LCD_Write_Cmd(0x3A); // Set Pixel format |
f3d | 80:ff42f77928ad | 41 | LCD_Write_Data(0x55); // To 16 bits per pixel |
f3d | 80:ff42f77928ad | 42 | |
f3d | 80:ff42f77928ad | 43 | LCD_Write_Cmd(0xB1); // Frame rate control |
f3d | 80:ff42f77928ad | 44 | LCD_Write_Data(0x00); // Use Fosc without divisor |
f3d | 80:ff42f77928ad | 45 | LCD_Write_Data(0x1B); // set 70Hz refresh rate |
f3d | 80:ff42f77928ad | 46 | |
f3d | 80:ff42f77928ad | 47 | LCD_Write_Cmd(0xB6); // Display Function Control |
f3d | 80:ff42f77928ad | 48 | LCD_Write_Data(0x00); // Use default values |
f3d | 80:ff42f77928ad | 49 | LCD_Write_Data(0x82); |
f3d | 81:7087ba9d18bb | 50 | LCD_Write_Data(0x27); |
f3d | 80:ff42f77928ad | 51 | LCD_Write_Cmd(0x11); //Exit Sleep |
f3d | 80:ff42f77928ad | 52 | wait(0.120); |
f3d | 81:7087ba9d18bb | 53 | |
f3d | 80:ff42f77928ad | 54 | LCD_Write_Cmd(0x29); //Display on |
f3d | 80:ff42f77928ad | 55 | LCD_Write_Cmd(0x2c); |
f3d | 80:ff42f77928ad | 56 | wait(0.005); |
f3d | 80:ff42f77928ad | 57 | |
f3d | 81:7087ba9d18bb | 58 | fillRectangle(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,RGBToWord(0x00,0,0)); |
f3d | 81:7087ba9d18bb | 59 | D_CS = 1; |
f3d | 81:7087ba9d18bb | 60 | |
f3d | 80:ff42f77928ad | 61 | } |
f3d | 80:ff42f77928ad | 62 | |
f3d | 80:ff42f77928ad | 63 | void Display::CommandMode() |
f3d | 80:ff42f77928ad | 64 | { |
f3d | 80:ff42f77928ad | 65 | DC = 0; |
f3d | 80:ff42f77928ad | 66 | } |
f3d | 80:ff42f77928ad | 67 | void Display::DataMode() |
f3d | 80:ff42f77928ad | 68 | { |
f3d | 80:ff42f77928ad | 69 | DC = 1; |
f3d | 80:ff42f77928ad | 70 | } |
f3d | 80:ff42f77928ad | 71 | void Display::LCD_Write_Cmd(uint8_t cmd) |
f3d | 80:ff42f77928ad | 72 | { |
f3d | 81:7087ba9d18bb | 73 | |
f3d | 80:ff42f77928ad | 74 | CommandMode(); |
f3d | 81:7087ba9d18bb | 75 | D_CS = 0; |
f3d | 80:ff42f77928ad | 76 | spi.write(cmd); |
f3d | 81:7087ba9d18bb | 77 | D_CS = 1; |
f3d | 80:ff42f77928ad | 78 | } |
f3d | 80:ff42f77928ad | 79 | void Display::LCD_Write_Data(uint8_t data) |
f3d | 80:ff42f77928ad | 80 | { |
f3d | 81:7087ba9d18bb | 81 | |
f3d | 80:ff42f77928ad | 82 | DataMode(); |
f3d | 81:7087ba9d18bb | 83 | D_CS = 0; |
f3d | 80:ff42f77928ad | 84 | spi.write(data); |
f3d | 81:7087ba9d18bb | 85 | D_CS = 1; |
f3d | 80:ff42f77928ad | 86 | } |
f3d | 80:ff42f77928ad | 87 | void Display::resetDisplay() |
f3d | 80:ff42f77928ad | 88 | { |
f3d | 80:ff42f77928ad | 89 | Rst = 0; |
f3d | 80:ff42f77928ad | 90 | wait(0.01); |
f3d | 80:ff42f77928ad | 91 | Rst = 1; |
f3d | 80:ff42f77928ad | 92 | wait(0.12); |
f3d | 80:ff42f77928ad | 93 | } |
f3d | 80:ff42f77928ad | 94 | void Display::openAperture(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2) |
f3d | 80:ff42f77928ad | 95 | { |
f3d | 80:ff42f77928ad | 96 | LCD_Write_Cmd(0x2a); |
f3d | 80:ff42f77928ad | 97 | LCD_Write_Data(x1>>8); |
f3d | 80:ff42f77928ad | 98 | LCD_Write_Data(x1); |
f3d | 80:ff42f77928ad | 99 | LCD_Write_Data(x2>>8); |
f3d | 80:ff42f77928ad | 100 | LCD_Write_Data(x2); |
f3d | 80:ff42f77928ad | 101 | LCD_Write_Cmd(0x2b); |
f3d | 80:ff42f77928ad | 102 | LCD_Write_Data(y1>>8); |
f3d | 80:ff42f77928ad | 103 | LCD_Write_Data(y1); |
f3d | 80:ff42f77928ad | 104 | LCD_Write_Data(y2>>8); |
f3d | 80:ff42f77928ad | 105 | LCD_Write_Data(y2); |
f3d | 80:ff42f77928ad | 106 | LCD_Write_Cmd(0x2c); |
f3d | 80:ff42f77928ad | 107 | } |
f3d | 80:ff42f77928ad | 108 | // Simple Pixel drawing routines |
f3d | 80:ff42f77928ad | 109 | void Display::putPixel(uint16_t x, uint16_t y, uint16_t Colour) |
f3d | 80:ff42f77928ad | 110 | { |
f3d | 80:ff42f77928ad | 111 | uint16_t rx; |
f3d | 81:7087ba9d18bb | 112 | |
f3d | 80:ff42f77928ad | 113 | openAperture(x,y,x+1,y+1); |
f3d | 80:ff42f77928ad | 114 | DataMode(); |
f3d | 81:7087ba9d18bb | 115 | D_CS = 0; |
f3d | 80:ff42f77928ad | 116 | spi.write((const char *) &Colour,2,(char *)&rx,0); |
f3d | 81:7087ba9d18bb | 117 | D_CS = 1; |
f3d | 80:ff42f77928ad | 118 | } |
f3d | 81:7087ba9d18bb | 119 | void Display::putImage(uint16_t xofs, uint16_t yofs, uint16_t width, uint16_t height, const uint16_t *Image) |
f3d | 80:ff42f77928ad | 120 | { |
f3d | 80:ff42f77928ad | 121 | uint16_t rx; |
f3d | 80:ff42f77928ad | 122 | uint16_t Colour; |
f3d | 81:7087ba9d18bb | 123 | |
f3d | 81:7087ba9d18bb | 124 | uint16_t x,y; |
f3d | 81:7087ba9d18bb | 125 | for (y = 0; y < height; y++) { |
f3d | 80:ff42f77928ad | 126 | for (x=0; x < width; x++) |
f3d | 80:ff42f77928ad | 127 | { |
f3d | 81:7087ba9d18bb | 128 | Colour = *(Image++); |
f3d | 81:7087ba9d18bb | 129 | putPixel(x+xofs,y+yofs,Colour); |
f3d | 81:7087ba9d18bb | 130 | } |
f3d | 81:7087ba9d18bb | 131 | } |
f3d | 80:ff42f77928ad | 132 | } |
f3d | 80:ff42f77928ad | 133 | void Display::fillRectangle(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t Colour) |
f3d | 80:ff42f77928ad | 134 | { |
f3d | 80:ff42f77928ad | 135 | /* in an effort to reduce overhead here a large word buffer is created. If the number of words to |
f3d | 80:ff42f77928ad | 136 | to write is greater than or equal to the size of this buffer then it is filled with the relevant colour |
f3d | 80:ff42f77928ad | 137 | and used as the source of data in the spi.write function. This greatly speeds up the writing of |
f3d | 80:ff42f77928ad | 138 | large arease of the screen. The choice of buffer size is interesting. |
f3d | 80:ff42f77928ad | 139 | */ |
f3d | 80:ff42f77928ad | 140 | #define BUF_SIZE 32 |
f3d | 80:ff42f77928ad | 141 | uint16_t rx; |
f3d | 80:ff42f77928ad | 142 | uint16_t txBuffer[BUF_SIZE]; |
f3d | 81:7087ba9d18bb | 143 | int count; |
f3d | 80:ff42f77928ad | 144 | openAperture(x,y,width,height); |
f3d | 80:ff42f77928ad | 145 | DataMode(); |
f3d | 81:7087ba9d18bb | 146 | D_CS = 0; |
f3d | 80:ff42f77928ad | 147 | count = (width*height)/BUF_SIZE; |
f3d | 80:ff42f77928ad | 148 | if (count) |
f3d | 80:ff42f77928ad | 149 | { // big area |
f3d | 80:ff42f77928ad | 150 | for (int i=0;i<BUF_SIZE;i++) |
f3d | 80:ff42f77928ad | 151 | { |
f3d | 80:ff42f77928ad | 152 | txBuffer[i]=Colour; |
f3d | 80:ff42f77928ad | 153 | } |
f3d | 80:ff42f77928ad | 154 | while(count--) |
f3d | 80:ff42f77928ad | 155 | { |
f3d | 80:ff42f77928ad | 156 | spi.write((const char *)txBuffer,2*BUF_SIZE,(char *)&rx,0); |
f3d | 80:ff42f77928ad | 157 | } |
f3d | 80:ff42f77928ad | 158 | count = (width*height)%BUF_SIZE; // write remainder of block |
f3d | 80:ff42f77928ad | 159 | while (count--) |
f3d | 80:ff42f77928ad | 160 | { |
f3d | 80:ff42f77928ad | 161 | spi.write((const char *) &Colour,2,(char *)&rx,0); // write a block of colour |
f3d | 80:ff42f77928ad | 162 | } |
f3d | 80:ff42f77928ad | 163 | |
f3d | 80:ff42f77928ad | 164 | } |
f3d | 80:ff42f77928ad | 165 | else |
f3d | 80:ff42f77928ad | 166 | { |
f3d | 80:ff42f77928ad | 167 | // small area so write 1 word at a time. |
f3d | 80:ff42f77928ad | 168 | count = (width*height); |
f3d | 80:ff42f77928ad | 169 | while(count--) |
f3d | 80:ff42f77928ad | 170 | { |
f3d | 80:ff42f77928ad | 171 | spi.write((const char *) &Colour,2,(char *)&rx,0); |
f3d | 80:ff42f77928ad | 172 | } |
f3d | 80:ff42f77928ad | 173 | |
f3d | 80:ff42f77928ad | 174 | } |
f3d | 81:7087ba9d18bb | 175 | D_CS = 1; |
f3d | 80:ff42f77928ad | 176 | } |
f3d | 80:ff42f77928ad | 177 | |
f3d | 80:ff42f77928ad | 178 | void Display::drawLineLowSlope(uint16_t x0, uint16_t y0, uint16_t x1,uint16_t y1, uint16_t Colour) |
f3d | 80:ff42f77928ad | 179 | { |
f3d | 80:ff42f77928ad | 180 | // Reference : https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm |
f3d | 80:ff42f77928ad | 181 | int dx = x1 - x0; |
f3d | 80:ff42f77928ad | 182 | int dy = y1 - y0; |
f3d | 80:ff42f77928ad | 183 | int yi = 1; |
f3d | 80:ff42f77928ad | 184 | if (dy < 0) |
f3d | 80:ff42f77928ad | 185 | { |
f3d | 80:ff42f77928ad | 186 | yi = -1; |
f3d | 80:ff42f77928ad | 187 | dy = -dy; |
f3d | 80:ff42f77928ad | 188 | } |
f3d | 80:ff42f77928ad | 189 | int D = 2*dy - dx; |
f3d | 80:ff42f77928ad | 190 | |
f3d | 80:ff42f77928ad | 191 | int y = y0; |
f3d | 80:ff42f77928ad | 192 | |
f3d | 80:ff42f77928ad | 193 | for (int x=x0; x <= x1;x++) |
f3d | 80:ff42f77928ad | 194 | { |
f3d | 80:ff42f77928ad | 195 | putPixel(x,y,Colour); |
f3d | 80:ff42f77928ad | 196 | if (D > 0) |
f3d | 80:ff42f77928ad | 197 | { |
f3d | 80:ff42f77928ad | 198 | y = y + yi; |
f3d | 80:ff42f77928ad | 199 | D = D - 2*dx; |
f3d | 80:ff42f77928ad | 200 | } |
f3d | 80:ff42f77928ad | 201 | D = D + 2*dy; |
f3d | 80:ff42f77928ad | 202 | |
f3d | 80:ff42f77928ad | 203 | } |
f3d | 80:ff42f77928ad | 204 | } |
f3d | 80:ff42f77928ad | 205 | |
f3d | 80:ff42f77928ad | 206 | void Display::drawLineHighSlope(uint16_t x0, uint16_t y0, uint16_t x1,uint16_t y1, uint16_t Colour) |
f3d | 80:ff42f77928ad | 207 | { |
f3d | 80:ff42f77928ad | 208 | // Reference : https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm |
f3d | 80:ff42f77928ad | 209 | |
f3d | 80:ff42f77928ad | 210 | int dx = x1 - x0; |
f3d | 80:ff42f77928ad | 211 | int dy = y1 - y0; |
f3d | 80:ff42f77928ad | 212 | int xi = 1; |
f3d | 80:ff42f77928ad | 213 | if (dx < 0) |
f3d | 80:ff42f77928ad | 214 | { |
f3d | 80:ff42f77928ad | 215 | xi = -1; |
f3d | 80:ff42f77928ad | 216 | dx = -dx; |
f3d | 80:ff42f77928ad | 217 | } |
f3d | 80:ff42f77928ad | 218 | int D = 2*dx - dy; |
f3d | 80:ff42f77928ad | 219 | int x = x0; |
f3d | 80:ff42f77928ad | 220 | |
f3d | 80:ff42f77928ad | 221 | for (int y=y0; y <= y1; y++) |
f3d | 80:ff42f77928ad | 222 | { |
f3d | 80:ff42f77928ad | 223 | putPixel(x,y,Colour); |
f3d | 80:ff42f77928ad | 224 | if (D > 0) |
f3d | 80:ff42f77928ad | 225 | { |
f3d | 80:ff42f77928ad | 226 | x = x + xi; |
f3d | 80:ff42f77928ad | 227 | D = D - 2*dy; |
f3d | 80:ff42f77928ad | 228 | } |
f3d | 80:ff42f77928ad | 229 | D = D + 2*dx; |
f3d | 80:ff42f77928ad | 230 | } |
f3d | 80:ff42f77928ad | 231 | } |
f3d | 80:ff42f77928ad | 232 | void Display::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t Colour) |
f3d | 80:ff42f77928ad | 233 | { |
f3d | 80:ff42f77928ad | 234 | // Reference : https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm |
f3d | 81:7087ba9d18bb | 235 | D_CS = 0; |
f3d | 80:ff42f77928ad | 236 | if ( iabs(y1 - y0) < iabs(x1 - x0) ) |
f3d | 80:ff42f77928ad | 237 | { |
f3d | 80:ff42f77928ad | 238 | if (x0 > x1) |
f3d | 80:ff42f77928ad | 239 | { |
f3d | 80:ff42f77928ad | 240 | drawLineLowSlope(x1, y1, x0, y0, Colour); |
f3d | 80:ff42f77928ad | 241 | } |
f3d | 80:ff42f77928ad | 242 | else |
f3d | 80:ff42f77928ad | 243 | { |
f3d | 80:ff42f77928ad | 244 | drawLineLowSlope(x0, y0, x1, y1, Colour); |
f3d | 80:ff42f77928ad | 245 | } |
f3d | 80:ff42f77928ad | 246 | } |
f3d | 80:ff42f77928ad | 247 | else |
f3d | 80:ff42f77928ad | 248 | { |
f3d | 80:ff42f77928ad | 249 | if (y0 > y1) |
f3d | 80:ff42f77928ad | 250 | { |
f3d | 80:ff42f77928ad | 251 | drawLineHighSlope(x1, y1, x0, y0, Colour); |
f3d | 80:ff42f77928ad | 252 | } |
f3d | 80:ff42f77928ad | 253 | else |
f3d | 80:ff42f77928ad | 254 | { |
f3d | 80:ff42f77928ad | 255 | drawLineHighSlope(x0, y0, x1, y1, Colour); |
f3d | 80:ff42f77928ad | 256 | } |
f3d | 80:ff42f77928ad | 257 | |
f3d | 80:ff42f77928ad | 258 | } |
f3d | 81:7087ba9d18bb | 259 | D_CS = 1; |
f3d | 80:ff42f77928ad | 260 | } |
f3d | 80:ff42f77928ad | 261 | |
f3d | 80:ff42f77928ad | 262 | |
f3d | 80:ff42f77928ad | 263 | uint16_t Display::RGBToWord(uint16_t R, uint16_t G, uint16_t B) |
f3d | 80:ff42f77928ad | 264 | { |
f3d | 80:ff42f77928ad | 265 | uint16_t rvalue = 0; |
f3d | 80:ff42f77928ad | 266 | rvalue += G >> 5; |
f3d | 80:ff42f77928ad | 267 | rvalue += (G & (0b111)) << 13; |
f3d | 80:ff42f77928ad | 268 | rvalue += (B >> 3) << 8; |
f3d | 80:ff42f77928ad | 269 | rvalue += (R >> 3) << 3; |
f3d | 80:ff42f77928ad | 270 | return rvalue; |
f3d | 80:ff42f77928ad | 271 | } |
f3d | 80:ff42f77928ad | 272 | void Display::drawRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t Colour) |
f3d | 80:ff42f77928ad | 273 | { |
f3d | 80:ff42f77928ad | 274 | drawLine(x,y,x+w,y,Colour); |
f3d | 80:ff42f77928ad | 275 | drawLine(x,y,x,y+h,Colour); |
f3d | 80:ff42f77928ad | 276 | drawLine(x+w,y,x+w,y+h,Colour); |
f3d | 80:ff42f77928ad | 277 | drawLine(x,y+h,x+w,y+h,Colour); |
f3d | 80:ff42f77928ad | 278 | } |
f3d | 80:ff42f77928ad | 279 | |
f3d | 80:ff42f77928ad | 280 | void Display::drawCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t Colour) |
f3d | 80:ff42f77928ad | 281 | { |
f3d | 80:ff42f77928ad | 282 | // Reference : https://en.wikipedia.org/wiki/Midpoint_circle_algorithm |
f3d | 80:ff42f77928ad | 283 | int x = radius-1; |
f3d | 80:ff42f77928ad | 284 | int y = 0; |
f3d | 80:ff42f77928ad | 285 | int dx = 1; |
f3d | 80:ff42f77928ad | 286 | int dy = 1; |
f3d | 80:ff42f77928ad | 287 | int err = dx - (radius << 1); |
f3d | 80:ff42f77928ad | 288 | if (radius > x0) |
f3d | 80:ff42f77928ad | 289 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 290 | if (radius > y0) |
f3d | 80:ff42f77928ad | 291 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 292 | |
f3d | 80:ff42f77928ad | 293 | if ((x0+radius) > SCREEN_WIDTH) |
f3d | 80:ff42f77928ad | 294 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 295 | if ((y0+radius) > SCREEN_HEIGHT) |
f3d | 80:ff42f77928ad | 296 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 297 | while (x >= y) |
f3d | 80:ff42f77928ad | 298 | { |
f3d | 80:ff42f77928ad | 299 | putPixel(x0 + x, y0 + y, Colour); |
f3d | 80:ff42f77928ad | 300 | putPixel(x0 + y, y0 + x, Colour); |
f3d | 80:ff42f77928ad | 301 | putPixel(x0 - y, y0 + x, Colour); |
f3d | 80:ff42f77928ad | 302 | putPixel(x0 - x, y0 + y, Colour); |
f3d | 80:ff42f77928ad | 303 | putPixel(x0 - x, y0 - y, Colour); |
f3d | 80:ff42f77928ad | 304 | putPixel(x0 - y, y0 - x, Colour); |
f3d | 80:ff42f77928ad | 305 | putPixel(x0 + y, y0 - x, Colour); |
f3d | 80:ff42f77928ad | 306 | putPixel(x0 + x, y0 - y, Colour); |
f3d | 80:ff42f77928ad | 307 | |
f3d | 80:ff42f77928ad | 308 | if (err <= 0) |
f3d | 80:ff42f77928ad | 309 | { |
f3d | 80:ff42f77928ad | 310 | y++; |
f3d | 80:ff42f77928ad | 311 | err += dy; |
f3d | 80:ff42f77928ad | 312 | dy += 2; |
f3d | 80:ff42f77928ad | 313 | } |
f3d | 80:ff42f77928ad | 314 | |
f3d | 80:ff42f77928ad | 315 | if (err > 0) |
f3d | 80:ff42f77928ad | 316 | { |
f3d | 80:ff42f77928ad | 317 | x--; |
f3d | 80:ff42f77928ad | 318 | dx += 2; |
f3d | 80:ff42f77928ad | 319 | err += dx - (radius << 1); |
f3d | 80:ff42f77928ad | 320 | } |
f3d | 80:ff42f77928ad | 321 | } |
f3d | 80:ff42f77928ad | 322 | } |
f3d | 80:ff42f77928ad | 323 | void Display::fillCircle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t Colour) |
f3d | 80:ff42f77928ad | 324 | { |
f3d | 80:ff42f77928ad | 325 | // Reference : https://en.wikipedia.org/wiki/Midpoint_circle_algorithm |
f3d | 80:ff42f77928ad | 326 | // Similar to drawCircle but fills the circle with lines instead |
f3d | 80:ff42f77928ad | 327 | int x = radius-1; |
f3d | 80:ff42f77928ad | 328 | int y = 0; |
f3d | 80:ff42f77928ad | 329 | int dx = 1; |
f3d | 80:ff42f77928ad | 330 | int dy = 1; |
f3d | 80:ff42f77928ad | 331 | int err = dx - (radius << 1); |
f3d | 80:ff42f77928ad | 332 | |
f3d | 80:ff42f77928ad | 333 | if (radius > x0) |
f3d | 80:ff42f77928ad | 334 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 335 | if (radius > y0) |
f3d | 80:ff42f77928ad | 336 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 337 | |
f3d | 80:ff42f77928ad | 338 | if ((x0+radius) > SCREEN_WIDTH) |
f3d | 80:ff42f77928ad | 339 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 340 | if ((y0+radius) > SCREEN_HEIGHT) |
f3d | 80:ff42f77928ad | 341 | return; // don't draw even parially off-screen circles |
f3d | 80:ff42f77928ad | 342 | while (x >= y) |
f3d | 80:ff42f77928ad | 343 | { |
f3d | 80:ff42f77928ad | 344 | drawLine(x0 - x, y0 + y,x0 + x, y0 + y, Colour); |
f3d | 80:ff42f77928ad | 345 | drawLine(x0 - y, y0 + x,x0 + y, y0 + x, Colour); |
f3d | 80:ff42f77928ad | 346 | drawLine(x0 - x, y0 - y,x0 + x, y0 - y, Colour); |
f3d | 80:ff42f77928ad | 347 | drawLine(x0 - y, y0 - x,x0 + y, y0 - x, Colour); |
f3d | 80:ff42f77928ad | 348 | |
f3d | 80:ff42f77928ad | 349 | if (err <= 0) |
f3d | 80:ff42f77928ad | 350 | { |
f3d | 80:ff42f77928ad | 351 | y++; |
f3d | 80:ff42f77928ad | 352 | err += dy; |
f3d | 80:ff42f77928ad | 353 | dy += 2; |
f3d | 80:ff42f77928ad | 354 | } |
f3d | 80:ff42f77928ad | 355 | |
f3d | 80:ff42f77928ad | 356 | if (err > 0) |
f3d | 80:ff42f77928ad | 357 | { |
f3d | 80:ff42f77928ad | 358 | x--; |
f3d | 80:ff42f77928ad | 359 | dx += 2; |
f3d | 80:ff42f77928ad | 360 | err += dx - (radius << 1); |
f3d | 80:ff42f77928ad | 361 | } |
f3d | 80:ff42f77928ad | 362 | } |
f3d | 81:7087ba9d18bb | 363 | } |
f3d | 81:7087ba9d18bb | 364 | void Display::print(const char *Text, uint16_t len, uint16_t x, uint16_t y, uint16_t ForeColour, uint16_t BackColour) |
f3d | 81:7087ba9d18bb | 365 | { |
f3d | 81:7087ba9d18bb | 366 | // This function draws each character individually. It uses an array called TextBox as a temporary storage |
f3d | 81:7087ba9d18bb | 367 | // location to hold the dots for the character in question. It constructs the image of the character and then |
f3d | 81:7087ba9d18bb | 368 | // calls on putImage to place it on the screen |
f3d | 81:7087ba9d18bb | 369 | uint8_t Index = 0; |
f3d | 81:7087ba9d18bb | 370 | uint8_t Row, Col; |
f3d | 81:7087ba9d18bb | 371 | const uint8_t *CharacterCode = 0; |
f3d | 81:7087ba9d18bb | 372 | uint16_t TextBox[FONT_WIDTH * FONT_HEIGHT]; |
f3d | 81:7087ba9d18bb | 373 | for (Index = 0; Index < len; Index++) |
f3d | 81:7087ba9d18bb | 374 | { |
f3d | 81:7087ba9d18bb | 375 | CharacterCode = &Font5x7[FONT_WIDTH * (Text[Index] - 32)]; |
f3d | 81:7087ba9d18bb | 376 | Col = 0; |
f3d | 81:7087ba9d18bb | 377 | while (Col < FONT_WIDTH) |
f3d | 81:7087ba9d18bb | 378 | { |
f3d | 81:7087ba9d18bb | 379 | Row = 0; |
f3d | 81:7087ba9d18bb | 380 | while (Row < FONT_HEIGHT) |
f3d | 81:7087ba9d18bb | 381 | { |
f3d | 81:7087ba9d18bb | 382 | if (CharacterCode[Col] & (1 << Row)) |
f3d | 81:7087ba9d18bb | 383 | { |
f3d | 81:7087ba9d18bb | 384 | TextBox[(Row * FONT_WIDTH) + Col] = ForeColour; |
f3d | 81:7087ba9d18bb | 385 | } |
f3d | 81:7087ba9d18bb | 386 | else |
f3d | 81:7087ba9d18bb | 387 | { |
f3d | 81:7087ba9d18bb | 388 | TextBox[(Row * FONT_WIDTH) + Col] = BackColour; |
f3d | 81:7087ba9d18bb | 389 | } |
f3d | 81:7087ba9d18bb | 390 | Row++; |
f3d | 81:7087ba9d18bb | 391 | } |
f3d | 81:7087ba9d18bb | 392 | Col++; |
f3d | 81:7087ba9d18bb | 393 | } |
f3d | 81:7087ba9d18bb | 394 | putImage(x, y, FONT_WIDTH, FONT_HEIGHT, (const uint16_t *)TextBox); |
f3d | 81:7087ba9d18bb | 395 | x = x + FONT_WIDTH + 2; |
f3d | 81:7087ba9d18bb | 396 | } |
f3d | 81:7087ba9d18bb | 397 | } |
f3d | 81:7087ba9d18bb | 398 | void Display::print(uint16_t Number, uint16_t x, uint16_t y, uint16_t ForeColour, uint16_t BackColour) |
f3d | 81:7087ba9d18bb | 399 | { |
f3d | 81:7087ba9d18bb | 400 | // This function converts the supplied number into a character string and then calls on puText to |
f3d | 81:7087ba9d18bb | 401 | // write it to the display |
f3d | 81:7087ba9d18bb | 402 | char Buffer[5]; // Maximum value = 65535 |
f3d | 81:7087ba9d18bb | 403 | Buffer[4] = Number % 10 + '0'; |
f3d | 81:7087ba9d18bb | 404 | Number = Number / 10; |
f3d | 81:7087ba9d18bb | 405 | Buffer[3] = Number % 10 + '0'; |
f3d | 81:7087ba9d18bb | 406 | Number = Number / 10; |
f3d | 81:7087ba9d18bb | 407 | Buffer[2] = Number % 10 + '0'; |
f3d | 81:7087ba9d18bb | 408 | Number = Number / 10; |
f3d | 81:7087ba9d18bb | 409 | Buffer[1] = Number % 10 + '0'; |
f3d | 81:7087ba9d18bb | 410 | Number = Number / 10; |
f3d | 81:7087ba9d18bb | 411 | Buffer[0] = Number % 10 + '0'; |
f3d | 81:7087ba9d18bb | 412 | print(Buffer, 5, x, y, ForeColour, BackColour); |
f3d | 81:7087ba9d18bb | 413 | } |
f3d | 81:7087ba9d18bb | 414 | void Display::initTouch(void) |
f3d | 81:7087ba9d18bb | 415 | { |
f3d | 81:7087ba9d18bb | 416 | // This display module has an XPT2046 touch screen controller connected over the SPI interface |
f3d | 81:7087ba9d18bb | 417 | // The XPT2046 |
f3d | 81:7087ba9d18bb | 418 | T_CS = 0; |
f3d | 81:7087ba9d18bb | 419 | spi.write(0b10011000); // 8 bit conversion, ratiometric measurement, read XP |
f3d | 81:7087ba9d18bb | 420 | //wait_us(100); |
f3d | 81:7087ba9d18bb | 421 | uint16_t indata,outdata; |
f3d | 81:7087ba9d18bb | 422 | outdata = 0xffff; |
f3d | 81:7087ba9d18bb | 423 | spi.write((const char *) &outdata,2,(char *)&indata,2); // write a block of colour |
f3d | 81:7087ba9d18bb | 424 | T_CS = 1; |
f3d | 81:7087ba9d18bb | 425 | } |
f3d | 81:7087ba9d18bb | 426 | uint16_t Display::readYTouch(void) |
f3d | 81:7087ba9d18bb | 427 | { |
f3d | 81:7087ba9d18bb | 428 | // This display module has an XPT2046 touch screen controller connected over the SPI interface |
f3d | 81:7087ba9d18bb | 429 | // The XPT2046 |
f3d | 81:7087ba9d18bb | 430 | /* |
f3d | 81:7087ba9d18bb | 431 | Format of command word : |
f3d | 81:7087ba9d18bb | 432 | b7 : must be 1 |
f3d | 81:7087ba9d18bb | 433 | b6,5,4 : A2,A1,A0 |
f3d | 81:7087ba9d18bb | 434 | 000 : temperature |
f3d | 81:7087ba9d18bb | 435 | |
f3d | 81:7087ba9d18bb | 436 | b3 : Mode |
f3d | 81:7087ba9d18bb | 437 | b2 : SER,DFR |
f3d | 81:7087ba9d18bb | 438 | b1,0 : PD1,PD0 |
f3d | 81:7087ba9d18bb | 439 | */ |
f3d | 81:7087ba9d18bb | 440 | uint16_t indata,outdata; |
f3d | 81:7087ba9d18bb | 441 | spi.frequency(2000000); // Can't run the touch screen controller at high speed |
f3d | 81:7087ba9d18bb | 442 | T_CS = 0; |
f3d | 81:7087ba9d18bb | 443 | spi.write((uint8_t)0b10011000); // 12 bit conversion, ratiometric measurement, reference off |
f3d | 81:7087ba9d18bb | 444 | // read XP which tells us Y (see diagram in datasheet) |
f3d | 81:7087ba9d18bb | 445 | wait_us(20); |
f3d | 81:7087ba9d18bb | 446 | outdata = 0xffff; |
f3d | 81:7087ba9d18bb | 447 | spi.write((const char *) &outdata,2,(char *)&indata,2); |
f3d | 81:7087ba9d18bb | 448 | T_CS = 1; |
f3d | 81:7087ba9d18bb | 449 | spi.frequency(8000000); |
f3d | 81:7087ba9d18bb | 450 | int calibrated_return= (indata>>12)+((indata & 0xff)<<4); |
f3d | 81:7087ba9d18bb | 451 | calibrated_return = (calibrated_return - Y_TOUCH_MIN); |
f3d | 81:7087ba9d18bb | 452 | if (calibrated_return < 0) |
f3d | 81:7087ba9d18bb | 453 | calibrated_return = 0; |
f3d | 81:7087ba9d18bb | 454 | calibrated_return = (calibrated_return * SCREEN_HEIGHT) / (Y_TOUCH_MAX - Y_TOUCH_MIN) ; |
f3d | 81:7087ba9d18bb | 455 | return calibrated_return; |
f3d | 81:7087ba9d18bb | 456 | } |
f3d | 81:7087ba9d18bb | 457 | uint16_t Display::readXTouch(void) |
f3d | 81:7087ba9d18bb | 458 | { |
f3d | 81:7087ba9d18bb | 459 | // This display module has an XPT2046 touch screen controller connected over the SPI interface |
f3d | 81:7087ba9d18bb | 460 | // The XPT2046 |
f3d | 81:7087ba9d18bb | 461 | /* |
f3d | 81:7087ba9d18bb | 462 | Format of command word : |
f3d | 81:7087ba9d18bb | 463 | b7 : must be 1 |
f3d | 81:7087ba9d18bb | 464 | b6,5,4 : A2,A1,A0 |
f3d | 81:7087ba9d18bb | 465 | 000 : temperature |
f3d | 81:7087ba9d18bb | 466 | |
f3d | 81:7087ba9d18bb | 467 | b3 : Mode |
f3d | 81:7087ba9d18bb | 468 | b2 : SER,DFR |
f3d | 81:7087ba9d18bb | 469 | b1,0 : PD1,PD0 |
f3d | 81:7087ba9d18bb | 470 | */ |
f3d | 81:7087ba9d18bb | 471 | uint16_t indata,outdata; |
f3d | 81:7087ba9d18bb | 472 | spi.frequency(2000000);// Can't run the touch screen controller at high speed |
f3d | 81:7087ba9d18bb | 473 | T_CS = 0; |
f3d | 81:7087ba9d18bb | 474 | spi.write((uint8_t)0b11011000); // 12 bit conversion, ratiometric measurement, reference off |
f3d | 81:7087ba9d18bb | 475 | // read YP which tells us X (see diagram in datasheet) |
f3d | 81:7087ba9d18bb | 476 | wait_us(20); |
f3d | 81:7087ba9d18bb | 477 | outdata = 0xffff; |
f3d | 81:7087ba9d18bb | 478 | spi.write((const char *) &outdata,2,(char *)&indata,2); |
f3d | 81:7087ba9d18bb | 479 | T_CS = 1; |
f3d | 81:7087ba9d18bb | 480 | spi.frequency(8000000); |
f3d | 81:7087ba9d18bb | 481 | int calibrated_return= (indata>>12)+((indata & 0xff)<<4); |
f3d | 81:7087ba9d18bb | 482 | calibrated_return = (calibrated_return - X_TOUCH_MIN); |
f3d | 81:7087ba9d18bb | 483 | if (calibrated_return < 0) |
f3d | 81:7087ba9d18bb | 484 | calibrated_return = 0; |
f3d | 81:7087ba9d18bb | 485 | calibrated_return = (calibrated_return * SCREEN_WIDTH) / (X_TOUCH_MAX - X_TOUCH_MIN); |
f3d | 81:7087ba9d18bb | 486 | // The X reading is backwards so need to subtract it from the screen width |
f3d | 81:7087ba9d18bb | 487 | calibrated_return = SCREEN_WIDTH - calibrated_return; |
f3d | 81:7087ba9d18bb | 488 | if (calibrated_return < 0) |
f3d | 81:7087ba9d18bb | 489 | calibrated_return = 0; |
f3d | 81:7087ba9d18bb | 490 | return calibrated_return; |
f3d | 81:7087ba9d18bb | 491 | } |
f3d | 81:7087ba9d18bb | 492 | int Display::penDown(void) |
f3d | 81:7087ba9d18bb | 493 | { |
f3d | 81:7087ba9d18bb | 494 | if (PenIRQ.read()==0) |
f3d | 81:7087ba9d18bb | 495 | return 1; |
f3d | 81:7087ba9d18bb | 496 | else |
f3d | 81:7087ba9d18bb | 497 | return 0; |
f3d | 80:ff42f77928ad | 498 | } |