/* * File: XPT2046.c * Author: MikroTronik * * Created on January 24, 2020, 5:23 PM */ #include #include #include #include #include #include "mcc_generated_files/mcc.h" #include "mcc_generated_files/spi3.h" #include "mcc_generated_files/pin_manager.h" #include "XPT2046.h" int32_t _cal_dx, _cal_dy, _cal_dvi, _cal_dvj; uint16_t _cal_vi1, _cal_vj1; uint16_t t_width, t_height; rotation_t _rot; inline static void swap(uint16_t *a, uint16_t *b) { uint16_t tmp = *a; *a = *b; *b = tmp; } void begin(uint16_t width, uint16_t height) { t_width = width; t_height = height; T_SCK_SetDigitalOutput(); T_CS_SetDigitalOutput(); T_DIN_SetDigitalOutput(); T_IRQ_SetDigitalInput(); T_CS_SetHigh(); T_SCK_SetHigh(); T_DIN_SetHigh(); T_CS_SetHigh(); } void setRotationTouch(rotation_t rot) { _rot = rot; } void getCalibrationPoints(uint16_t *x1, uint16_t *y1, uint16_t *x2, uint16_t *y2) { *x1 = *y1 = CAL_MARGIN; *x2 = t_width - CAL_MARGIN; *y2 = t_height - CAL_MARGIN; } void setCalibration(uint16_t vi1, uint16_t vj1, uint16_t vi2, uint16_t vj2) { _cal_dx = t_width - 2 * CAL_MARGIN; _cal_dy = t_height - 2 * CAL_MARGIN; _cal_vi1 = (int32_t) vi1; _cal_vj1 = (int32_t) vj1; _cal_dvi = (int32_t) vi2 - vi1; _cal_dvj = (int32_t) vj2 - vj1; } bool isTouching() { return T_IRQ_GetValue(); } void getRaw(uint16_t *vi, uint16_t *vj, adc_ref_t mode, uint8_t max_samples) { // uint8_t ctrl_lo = ((mode == MODE_DFR) ? CTRL_LO_DFR : CTRL_LO_SER); // uint32_t xx = 0, xx1 = 0; // uint32_t yy = 0, yy1 = 0; // uint8_t count = 0; // uint8_t i; // for ( i = 0; i < max_samples; i++) { // if (!isTouching()) { // T_CS_SetLow(); // /* Send command to read x- axis */ // SPI3_Exchange8bit(0x00); // SPI3_Exchange8bit(0x90); // // /* read-X */ // xx1 = SPI3_Exchange8bit(0); // xx1 = ((xx1 << 4)&0x0FF0); // xx += (xx1 + ((SPI3_Exchange8bit(0x00) >> 4)&0x0F)); // // // // // /* Send command to read y- axis */ // SPI3_Exchange8bit(0x00); // SPI3_Exchange8bit(0xD0); // // /* read -Y */ // yy1 = SPI3_Exchange8bit(0); // yy1 = ((yy1 << 4)&0x0FF0); // yy += (yy1 + ((SPI3_Exchange8bit(0x00) >> 4)&0x0F)); // // T_CS_SetHigh(); // count++; // } // } // *vi = (xx / count); // *vj = (yy / count); uint8_t ctrl_lo = ((mode == MODE_DFR) ? CTRL_LO_DFR : CTRL_LO_SER); T_CS_SetLow(); SPI3_Exchange8bit(CTRL_HI_X | ctrl_lo); // Send first control byte *vi = _readLoop(CTRL_HI_X | ctrl_lo, max_samples); *vj = _readLoop(CTRL_HI_Y | ctrl_lo, max_samples); if (mode == MODE_DFR) { // Turn off ADC by issuing one more read (throwaway) // This needs to be done, because PD=0b11 (needed for MODE_DFR) will disable PENIRQ SPI3_Exchange8bit(0); // Maintain 16-clocks/conversion; _readLoop always ends after issuing a control byte SPI3_Exchange8bit(CTRL_HI_Y | CTRL_LO_SER); } SPI3_Exchange8bit(0); // Flush last read, just to be sure SPI3_Exchange8bit(0); T_CS_SetHigh(); } void getPosition(uint16_t *x, uint16_t *y, adc_ref_t mode, uint8_t max_samples) { if (isTouching()) { *x = *y = 0xffff; return; } uint16_t vi = 0, vj = 0; getRaw(&vi, &vj, mode, max_samples); // Map to (un-rotated) display coordinates #if 1 *x = (uint16_t) (_cal_dx * (vj - _cal_vj1) / _cal_dvj + CAL_MARGIN); *y = (uint16_t) (_cal_dy * (vi - _cal_vi1) / _cal_dvi + CAL_MARGIN); #else *x = (uint16_t) (_cal_dx * (vi - _cal_vi1) / _cal_dvi + CAL_MARGIN); *y = (uint16_t) (_cal_dy * (vj - _cal_vj1) / _cal_dvj + CAL_MARGIN); #endif *x = *x & 0x0FFF; *y = *y & 0x0FFF; // Transform based on current rotation setting // TODO: Is it worth to do this by tweaking _cal_* values instead? switch (_rot) { // TODO double-check case ROT90: *x = abs(t_width - *x); swap(x, y); break; case ROT180: *x = abs(t_width - *x); *y = abs(t_height - *y); break; case ROT270: *y = abs(t_height - *y); swap(x, y); break; case ROT0: default: // Do nothing break; } } void powerDown() { } uint16_t _readLoop(uint8_t ctrl, uint8_t max_samples) { uint16_t prev = 0xffff, cur = 0xffff; uint8_t i = 0; do { prev = cur; cur = SPI3_Exchange8bit(0); cur = (cur << 4) | (SPI3_Exchange8bit(ctrl) >> 4); // 16 clocks -> 12-bits (zero-padded at end) } while ((prev != cur) && (++i < max_samples)); return cur; } /****************************************************************************************************************/