(ARM Cortex-A7) T113-S3 (MangoPi MQ-R)
分析XBoot GT911無法觸發中斷的原因
參考資料:
1. xboot
2. GT911
3. debugdump
T113-S3開發板
司徒手上並沒有GT911觸控板,因此,司徒使用Arduino Micro模擬GT911訊號
Arduino腳位:
T113-S3腳位:
司徒將GT911 I2C訊號接到T113-S3 I2C-2,GT911的中斷則是接到T113-S3 PB6(手動觸發)
杜邦線連接
Arduino模擬GT911程式
#include <Wire.h> unsigned short rx = 0; void receiveEvent(int howMany) { if(howMany == 2){ rx = Wire.read(); rx<<= 8; rx|= Wire.read(); } else{ while (Wire.available()) { Wire.read(); } } Serial.print("howMany:"); Serial.print(howMany); Serial.print("\n"); Serial.print("0x"); Serial.print(rx, HEX); Serial.print("\n"); } unsigned short x = 0; unsigned short y = 0; void requestEvent() { switch(rx){ case 0x8047: Wire.write(byte(0x01)); break; case 0x8140: Wire.write('A'); Wire.write('B'); Wire.write('C'); Wire.write('D'); break; case 0x8144: Wire.write(byte(0x12)); Wire.write(byte(0x34)); break; case 0x814e: Wire.write(byte(0x80 | 1)); break; case 0x814f: Wire.write(byte(0x01)); Wire.write(byte(x)); Wire.write(byte(x >> 8)); Wire.write(byte(y)); Wire.write(byte(y >> 8)); Wire.write(byte(0x00)); Wire.write(byte(0x00)); Wire.write(byte(0x00)); x+= 1; y+= 1; break; } rx = 0; } void setup() { Wire.begin(20); Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); Serial.begin(115200); } void loop() { delay(100); }
src/arch/arm32/mach-t113s3/romdisk/boot/mangopi.json
524 "i2c-t113:2@0x02502800": { 525 "clock-name": "bus-i2c2", 526 "clock-frequency": 400000, 527 "reset": 466, 528 "sda-gpio": 133, 529 "sda-gpio-config": 4, 530 "scl-gpio": 132, 531 "scl-gpio-config": 4 532 }, 662 "ts-gt911": { 663 "i2c-bus": "i2c-t113.2", 664 "slave-address": 20, 665 "interrupt-gpio": 38, 666 "interrupt-gpio-config": 14, 667 "reset-gpio": 34, 668 "reset-gpio-config": 1 669 },
src/arch/arm32/mach-t113s3/driver/ts-gt911.c
75 static bool_t gt911_write(struct i2c_device_t * dev, u16_t reg, u8_t * buf, int len) 76 { 77 struct i2c_msg_t msg; 78 u8_t mbuf[256]; 79 80 if(len > sizeof(mbuf) - 1) 81 len = sizeof(mbuf) - 1; 82 mbuf[0] = (reg >> 8) & 0xff; 83 mbuf[1] = (reg >> 0) & 0xff; 84 memcpy(&mbuf[2], buf, len); 85 86 msg.addr = dev->addr; 87 msg.flags = 0; 88 msg.len = 32;//len + 2; 89 msg.buf = &mbuf[0]; 90 91 if(i2c_transfer(dev->i2c, &msg, 1) != 1) 92 return FALSE; 93 return TRUE; 94 } 134 static bool_t gt911_initial(struct i2c_device_t * dev) 135 { 136 u8_t cfg; 137 u8_t id[4]; 138 u8_t ver[2]; 139 140 if(!gt911_read(dev, GT911_CONFIG_DATA, &cfg, 1)) 141 return FALSE; 142 if(!gt911_read(dev, GT911_PRODUCT_ID, &id[0], 4)) 143 return FALSE; 144 if(!gt911_read(dev, GT911_FIRMWARE_VERSION, &ver[0], 2)) 145 return FALSE; 146 147 LOG("GT911 Version: %c%c%c%c(0x%02x%02x)(0x%02x)\r\n", id[0], id[1], id[2], id[3], ver[1], ver[0], cfg); 148 return gt911_send_cfg(dev, (u8_t *)gt911_config_data, ARRAY_SIZE(gt911_config_data)); 149 } 151 static void gt911_interrupt(void * data) 152 { 153 struct input_t * input = (struct input_t *)data; 154 struct ts_gt911_pdata_t * pdat = (struct ts_gt911_pdata_t *)input->priv; 155 u8_t status, buf[40]; 156 u8_t * p; 157 int count, i; 158 int id, x, y; 159 160 LOG("%s++\r\n", __func__); 161 disable_irq(pdat->irq); 162 for(i = 0; i < 5; i++) 163 { 164 pdat->node[i].valid = 0; 165 } 166 if(gt911_read(pdat->dev, GT911_STATUS, &status, 1) && (status & (1 << 7))) 167 { 168 count = status & 0x0f; 169 if(count > 0 && count < 5) 170 { 171 if(gt911_read(pdat->dev, GT911_COOR_ADDR, &buf[0], count << 3)) 172 { 173 for(i = 0; i < count; i++) 174 { 175 p = &buf[i << 3]; 176 id = p[0]; 177 x = (p[2] << 8) | (p[1] << 0); 178 y = (p[4] << 8) | (p[3] << 0); 179 LOG("%s, count:%d, x:%d, y:%d\r\n", __func__, count, x, y); ... 209 enable_irq(pdat->irq); 210 LOG("%s--\r\n", __func__); 211 }
編譯、下載
$ make CROSS_COMPILE=arm-linux-gnueabihf- PLATFORM=arm32-t113s3 $ xfel ddr t113-s3 $ xfel write 0x40000000 output/xboot.bin $ xfel exec 0x40000000
Arduino GT911可以正常工作,但是,中斷PB6無法被觸發
[ 0.260214]GT911 Version: ABCD(0x3412)(0x01) [ 0.287074]Probe device 'ts-gt911.0' with ts-gt911
為了方便測試,司徒將PB6加上提昇電阻並且改成Falling中斷觸發
282 LOG("%s, gpio:%d, gpiocfg:%d, irqnum:%d\r\n", __func__, gpio, gpiocfg, irq); 283 if(gpio >= 0) 284 { 285 if(gpiocfg >= 0) 286 gpio_set_cfg(gpio, gpiocfg); 287 gpio_set_pull(gpio, GPIO_PULL_UP); 288 } 289 request_irq(pdat->irq, gt911_interrupt, IRQ_TYPE_EDGE_FALLING, input);
PB6=GPIO38、GPIOCFG=14、IRQ=262,這個IRQ應該是抓錯了?
[ 0.266982]ts_gt911_probe, gpio:38, gpiocfg:14, irqnum:262
src/arch/arm32/mach-t113s3/romdisk/boot/mangopi.json
388 "irq-gic400@0x03020000": { "interrupt-base": 32, "interrupt-count": 224 }, 389 "irq-t113-gpio@0x02000220": { "interrupt-base": 224, "interrupt-count": 8, "interrupt-parent": 101 }, 390 "irq-t113-gpio@0x02000240": { "interrupt-base": 256, "interrupt-count": 8, "interrupt-parent": 103 }, 391 "irq-t113-gpio@0x02000260": { "interrupt-base": 288, "interrupt-count": 23, "interrupt-parent": 105 }, 392 "irq-t113-gpio@0x02000280": { "interrupt-base": 320, "interrupt-count": 14, "interrupt-parent": 107 }, 393 "irq-t113-gpio@0x020002a0": { "interrupt-base": 352, "interrupt-count": 7, "interrupt-parent": 109 }, 394 "irq-t113-gpio@0x020002c0": { "interrupt-base": 384, "interrupt-count": 16, "interrupt-parent": 111 },
src/driver/interrupt/interrupt.c
191 bool_t request_irq(int irq, void (*func)(void *), enum irq_type_t type, void * data) 192 { 193 struct irqchip_t * chip; 194 int offset; 195 196 if(!func) 197 return FALSE; 198 199 chip = search_irqchip(irq); 200 if(!chip) 201 return FALSE; 202 203 offset = irq - chip->base; 204 if(chip->handler[offset].func != null_interrupt_function) { 205 return FALSE; 206 } 207 208 LOG("%s, irq:%d, chip->base:%d, offset:%d\r\n", __func__, irq, chip->base, offset);
XBoot修改到的中斷地址是屬於PC6,但是司徒的中斷是設定成PB6
[ 0.272634]request_irq, irq:262, chip->base:256, offset:6
src/arch/arm32/mach-t113s3/driver/irq-t113-gpio.c
92 addr = pdat->virt + GPIO_INT_CFG0 + ((offset >> 3) << 2); 93 val = read32(addr); 94 val &= ~(0xf << ((offset & 0x7) << 2)); 95 val |= ((cfg & 0x7) << ((offset & 0x7) << 2)); 96 write32(addr, val); 97 98 LOG("%s, addr:%p, type:%d, offset:%d\r\n", __func__, addr, type, offset);
果然修改到PC6 0x02000240
[ 0.268151]ts_gt911_probe, gpio:38, gpiocfg:14, irqnum:262 [ 0.273812]request_irq, irq:262, chip->base:256, offset:6 [ 0.279202]irq_t113_gpio_settype, addr:0x02000240, type:3, offset:6 [ 0.285373]Probe device 'ts-gt911.0' with ts-gt911
PB6是位於0x02000230
Workaround (src/driver/interrupt/interrupt.c)
62 static struct irqchip_t * search_irqchip(int irq) 63 { 64 struct device_t * pos, * n; 65 struct irqchip_t * chip; 66 67 list_for_each_entry_safe(pos, n, &__device_head[DEVICE_TYPE_IRQCHIP], head) 68 { 69 chip = (struct irqchip_t *)(pos->priv); 70 if(irq == 230){ 71 if(chip->base == 224){ 72 return chip; 73 } 74 continue; 75 } 76 if((irq >= chip->base) && (irq < (chip->base + chip->nirq))) 77 return chip; 78 } 79 return NULL; 80 } 191 bool_t request_irq(int irq, void (*func)(void *), enum irq_type_t type, void * data) 192 { 193 struct irqchip_t * chip; 194 int offset; 195 196 if(!func) 197 return FALSE; 198 199 if(irq == 262){ 200 irq-= 32; 201 }
修改後,就可以正常中斷觸發並且回報觸控點
[ 0.260653]GT911 Version: ABCD(0x3412)(0x01) [ 0.266935]ts_gt911_probe, gpio:38, gpiocfg:14, irqnum:262 [ 0.272326]request_irq, irq:230, chip->base:224, offset:6 [ 0.277959]irq_t113_gpio_settype, addr:0x02000220, type:3, offset:6 [ 0.299301]Probe device 'ts-gt911.0' with ts-gt911 [ 0.304091]Probe device 'g2d-t113.0' with g2d-t113 [ 0.310178]Probe device 'fb-t113-rgb.0' with fb-t113-rgb [ 0.315658]Probe device 'console-uart.0' with console-uart [ 0.322001]mount /private with 'ram' filesystem Press any key to stop auto boot: 0.000 xboot: /# [ 5.434256]gt911_interrupt++ [ 5.440101]gt911_interrupt, count:1, x:1, y:1 [ 5.446270]gt911_interrupt-- [ 9.054572]gt911_interrupt++ [ 9.060405]gt911_interrupt, count:1, x:2, y:2 [ 9.066782]gt911_interrupt--