diff --git a/src/pxa260/pxa260I2c.c b/src/pxa260/pxa260I2c.c index 6bc5872..63785ee 100644 --- a/src/pxa260/pxa260I2c.c +++ b/src/pxa260/pxa260I2c.c @@ -96,7 +96,7 @@ void pxa260I2cWriteWord(uint32_t address, uint32_t value){ } pxa260I2cUnitBusy = true; - pxa260TimingQueueEvent(PXA260_I2C_TRANSFER_DURATION, PXA260_TIMING_CALLBACK_I2C_RECEIVE_FULL); + pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_I2C_RECEIVE_FULL, PXA260_I2C_TRANSFER_DURATION); } else{ //send @@ -108,7 +108,7 @@ void pxa260I2cWriteWord(uint32_t address, uint32_t value){ tps65010I2cExchange((pxa260I2cBuffer & 1 << 7 - index) ? I2C_1 : I2C_0); pxa260I2cUnitBusy = true; - pxa260TimingQueueEvent(PXA260_I2C_TRANSFER_DURATION, PXA260_TIMING_CALLBACK_I2C_TRANSMIT_EMPTY); + pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_I2C_TRANSMIT_EMPTY, PXA260_I2C_TRANSFER_DURATION); } } if(value & 0x0002){ diff --git a/src/pxa260/pxa260Ssp.c b/src/pxa260/pxa260Ssp.c index 2fd7857..2593c36 100644 --- a/src/pxa260/pxa260Ssp.c +++ b/src/pxa260/pxa260Ssp.c @@ -209,7 +209,7 @@ void pxa260SspWriteWord(uint32_t address, uint32_t value){ pxa260SspTxFifoWrite(value); if(!pxa260SspTransfering){ pxa260SspTransfering = true; - pxa260TimingQueueEvent(PXA260_SSP_TRANSFER_DURATION, PXA260_TIMING_CALLBACK_SSP_TRANSFER_COMPLETE); + pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_SSP_TRANSFER_COMPLETE, PXA260_SSP_TRANSFER_DURATION); } pxa260SspUpdateInterrupt(); return; @@ -245,7 +245,7 @@ void pxa260SspTransferComplete(void){ //if still transmitting, need to enqueue next event if(pxa260SspTxFifoEntrys() > 0) - pxa260TimingQueueEvent(PXA260_SSP_TRANSFER_DURATION, PXA260_TIMING_CALLBACK_SSP_TRANSFER_COMPLETE); + pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_SSP_TRANSFER_COMPLETE, PXA260_SSP_TRANSFER_DURATION); else pxa260SspTransfering = false; diff --git a/src/pxa260/pxa260Timing.c b/src/pxa260/pxa260Timing.c index 5f0d330..c8147b7 100644 --- a/src/pxa260/pxa260Timing.c +++ b/src/pxa260/pxa260Timing.c @@ -2,6 +2,7 @@ #include #include +#include "../tsc2101.h" #include "../armv5te/os/os.h" #include "../armv5te/emu.h" #include "../armv5te/cpu.h" @@ -10,18 +11,21 @@ #include "pxa260Timing.h" -static int32_t pxa260TimingLeftoverCycles; +#define PXA260_TIMING_NEVER 0xFFFFFFFF -void (*pxa260TimingCallbacks[PXA260_TIMING_TOTAL_CALLBACKS])(void); -event_t pxa260TimingQueuedEvents[20]; + +static int32_t pxa260TimingLeftoverCycles;//doesnt need to go in save states + +void (*pxa260TimingCallbacks[PXA260_TIMING_TOTAL_CALLBACKS])(void); +int32_t pxa260TimingQueuedEvents[PXA260_TIMING_TOTAL_CALLBACKS]; static int32_t pxa260TimingGetDurationUntilNextEvent(int32_t duration/*call with how long you want to run*/){ uint8_t index; - for(index = 0; index < sizeof(pxa260TimingQueuedEvents) / sizeof(event_t); index++) - if(pxa260TimingQueuedEvents[index].active && pxa260TimingQueuedEvents[index].wait < duration) - duration = pxa260TimingQueuedEvents[index].wait; + for(index = 0; index < PXA260_TIMING_TOTAL_CALLBACKS; index++) + if(pxa260TimingQueuedEvents[index] != PXA260_TIMING_NEVER && pxa260TimingQueuedEvents[index] < duration) + duration = pxa260TimingQueuedEvents[index]; return duration; } @@ -30,30 +34,27 @@ void pxa260TimingInit(void){ pxa260TimingCallbacks[PXA260_TIMING_CALLBACK_I2C_TRANSMIT_EMPTY] = pxa260I2cTransmitEmpty; pxa260TimingCallbacks[PXA260_TIMING_CALLBACK_I2C_RECEIVE_FULL] = pxa260I2cReceiveFull; pxa260TimingCallbacks[PXA260_TIMING_CALLBACK_SSP_TRANSFER_COMPLETE] = pxa260SspTransferComplete; + pxa260TimingCallbacks[PXA260_TIMING_CALLBACK_TSC2101_SCAN] = tsc2101Scan; } void pxa260TimingReset(void){ - memset(pxa260TimingQueuedEvents, 0x00, sizeof(pxa260TimingQueuedEvents)); -} - -void pxa260TimingQueueEvent(int32_t wait, uint8_t callbackId){ uint8_t index; - for(index = 0; index < sizeof(pxa260TimingQueuedEvents) / sizeof(event_t); index++){ - if(!pxa260TimingQueuedEvents[index].active){ - //found empty slot, enqueue event - pxa260TimingQueuedEvents[index].wait = wait; - pxa260TimingQueuedEvents[index].callbackId = callbackId; - pxa260TimingQueuedEvents[index].active = true; - if(wait < -cycle_count_delta){ - pxa260TimingLeftoverCycles = -cycle_count_delta - wait; - cycle_count_delta = -wait; - } - return; - } - } + for(index = 0; index < PXA260_TIMING_TOTAL_CALLBACKS; index++) + pxa260TimingQueuedEvents[index] = PXA260_TIMING_NEVER; +} - debugLog("Unable to find CPU event slot!!!"); +void pxa260TimingTriggerEvent(uint8_t callbackId, int32_t wait){ + pxa260TimingQueuedEvents[callbackId] = wait; + //dont need to check if in handler since cycle_count_delta is 0 or positive when in handlers are called + if(wait < -cycle_count_delta){ + pxa260TimingLeftoverCycles = -cycle_count_delta - wait; + cycle_count_delta = -wait; + } +} + +void pxa260TimingCancelEvent(uint8_t callbackId){ + pxa260TimingQueuedEvents[callbackId] = PXA260_TIMING_NEVER; } void pxa260TimingRun(int32_t cycles){ @@ -104,13 +105,13 @@ void pxa260TimingRun(int32_t cycles){ addCycles -= pxa260TimingLeftoverCycles; pxa260TimingLeftoverCycles = 0; - for(index = 0; index < sizeof(pxa260TimingQueuedEvents) / sizeof(event_t); index++){ - if(pxa260TimingQueuedEvents[index].active){ - pxa260TimingQueuedEvents[index].wait -= addCycles; - if(pxa260TimingQueuedEvents[index].wait <= 0){ + for(index = 0; index < PXA260_TIMING_TOTAL_CALLBACKS; index++){ + if(pxa260TimingQueuedEvents[index] != PXA260_TIMING_NEVER){ + pxa260TimingQueuedEvents[index] -= addCycles; + if(pxa260TimingQueuedEvents[index] <= 0){ //execute event - pxa260TimingCallbacks[pxa260TimingQueuedEvents[index].callbackId](); - pxa260TimingQueuedEvents[index].active = false; + pxa260TimingQueuedEvents[index] = PXA260_TIMING_NEVER;//set to never before calling function because it may retrigger the event and we dont want the new one cleared + pxa260TimingCallbacks[index](); } } } diff --git a/src/pxa260/pxa260Timing.h b/src/pxa260/pxa260Timing.h index d4b8d6b..7c7d0a3 100644 --- a/src/pxa260/pxa260Timing.h +++ b/src/pxa260/pxa260Timing.h @@ -7,22 +7,18 @@ enum{ PXA260_TIMING_CALLBACK_I2C_TRANSMIT_EMPTY = 0, PXA260_TIMING_CALLBACK_I2C_RECEIVE_FULL, PXA260_TIMING_CALLBACK_SSP_TRANSFER_COMPLETE, + PXA260_TIMING_CALLBACK_TSC2101_SCAN, PXA260_TIMING_TOTAL_CALLBACKS }; -typedef struct{ - int32_t wait; - uint8_t callbackId; - bool active; -}event_t; - extern void (*pxa260TimingCallbacks[])(void);//saving a function pointer in a state is not portable and will crash even on the same system between program loads with ASLR -extern event_t pxa260TimingQueuedEvents[]; +extern int32_t pxa260TimingQueuedEvents[]; void pxa260TimingInit(void); void pxa260TimingReset(void); -void pxa260TimingQueueEvent(int32_t wait, uint8_t callbackId); +void pxa260TimingTriggerEvent(uint8_t callbackId, int32_t wait); +void pxa260TimingCancelEvent(uint8_t callbackId); void pxa260TimingRun(int32_t cycles);//this runs the CPU #endif diff --git a/src/tsc2101.c b/src/tsc2101.c index f42fe41..59aa77b 100644 --- a/src/tsc2101.c +++ b/src/tsc2101.c @@ -3,6 +3,7 @@ #include #include "emulator.h" +#include "pxa260/pxa260Timing.h" #include "tsc2101.h" @@ -11,7 +12,7 @@ //TODO: single shot/continuos modes //TODO: HCTLM is wrong - +#define TSC2101_SCAN_DURATION 10000//in PXA260 opcodes//TODO: this may need to be calculated based on the timing params in the registers #define TSC2101_REG_LOCATION(page, address) ((page) << 6 | (address)) enum{ @@ -173,7 +174,288 @@ static uint16_t tsc2101GetTemp2Value(void){ return 0x777 & tsc2101GetAnalogMask(); } -static void tsc2101Scan(void){ +static void tsc2101ResetRegisters(void){ + tsc2101HasNewData = 0x0000; + + memset(tsc2101Registers, 0x00, sizeof(tsc2101Registers)); + + //TODO: need to add all the registers here + tsc2101Registers[TOUCH_CONTROL_STATUS] = 0x8000; + tsc2101Registers[TOUCH_CONTROL_REFERENCE] = 0x0002; + //currenly at register 0x5 of touch control + + tsc2101RefreshInterrupt(); +} + +static uint16_t tsc2101RegisterRead(uint8_t page, uint8_t address){ + uint8_t combinedRegisterNumber = TSC2101_REG_LOCATION(page, address); + + switch(combinedRegisterNumber){ + case TOUCH_CONTROL_TSC_ADC: + return tsc2101Registers[TOUCH_CONTROL_TSC_ADC] & 0x3FFF | palmInput.touchscreenTouched << 15 | 1 << 14/*TODO: this states the ADC is never busy*/; + + case TOUCH_CONTROL_STATUS:{ + uint16_t value = tsc2101Registers[TOUCH_CONTROL_STATUS] & 0xF000; + + value |= !!(tsc2101HasNewData) << 10; + //TODO: not returning individual status bits yet + + debugLog("TSC2101 read status register\n"); + return value; + } + + case TOUCH_CONTROL_BUFFER_MODE: + return tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] | (tsc2101BufferFifoEntrys() == 64) << 10 | (tsc2101BufferFifoEntrys() == 0) << 9; + + case TOUCH_CONTROL_RESET_CONTROL_REGISTER: + return 0xFFFF; + + //TOUCH_DATA_* registers are scaned, the values get copyed to the register when the result is generated + case TOUCH_DATA_X: + case TOUCH_DATA_Y: + case TOUCH_DATA_Z1: + case TOUCH_DATA_Z2: + case TOUCH_DATA_BAT: + case TOUCH_DATA_AUX1: + case TOUCH_DATA_AUX2: + case TOUCH_DATA_TEMP1: + case TOUCH_DATA_TEMP2: + tsc2101HasNewData &= ~(1 << combinedRegisterNumber); + return tsc2101Registers[combinedRegisterNumber]; + + default: + if(page == 3) + return tsc2101BufferFifoRead(); + debugLog("Unimplemented TSC2101 register read, page:0x%01X, address:0x%02X\n", page, address); + return 0x0000;//TODO: this may need to be 0xFFFF + } +} + +static void tsc2101RegisterWrite(uint8_t page, uint8_t address, uint16_t value){ + uint8_t combinedRegisterNumber = TSC2101_REG_LOCATION(page, address); + + switch(combinedRegisterNumber){ + case TOUCH_CONTROL_TSC_ADC: + tsc2101Registers[TOUCH_CONTROL_TSC_ADC] = value; + pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_TSC2101_SCAN, TSC2101_SCAN_DURATION); + return; + + case TOUCH_CONTROL_STATUS: + tsc2101Registers[TOUCH_CONTROL_STATUS] = value & 0xC000; + tsc2101RefreshInterrupt();//interrupt type might have changed + return; + + case TOUCH_CONTROL_BUFFER_MODE: + if((tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] & 0x8000) && !(value & 0x8000)) + tsc2101BufferFifoFlush(); + + tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] = value & 0xF800; + tsc2101RefreshInterrupt();//need to refresh innterupt because the trigger level may have changed + return; + + case TOUCH_CONTROL_REFERENCE: + //TODO: may need to divide the values by the referece voltage then multiply by 0xFFF + tsc2101Registers[TOUCH_CONTROL_REFERENCE] = value & 0x001F; + return; + + case TOUCH_CONTROL_RESET_CONTROL_REGISTER: + if(value == 0xBB00) + tsc2101ResetRegisters(); + return; + + case TOUCH_CONTROL_CONFIGURATION: + //TODO: TOUCH_CONTROL_CONFIGURATION SWPDTD bit + debugLog("TSC2101 config register writes not fully implemented\n"); + tsc2101Registers[TOUCH_CONTROL_CONFIGURATION] = value & 0x007F; + tsc2101RefreshInterrupt(); + return; + + case TOUCH_CONTROL_TEMPERATURE_MAX: + case TOUCH_CONTROL_TEMPERATURE_MIN: + case TOUCH_CONTROL_AUX1_MAX: + case TOUCH_CONTROL_AUX1_MIN: + case TOUCH_CONTROL_AUX2_MAX: + case TOUCH_CONTROL_AUX2_MIN: + tsc2101Registers[combinedRegisterNumber] = value & 0x1FFF; + tsc2101RefreshInterrupt(); + return; + + case TOUCH_CONTROL_MEASUREMENT_CONFIGURATION: + tsc2101Registers[TOUCH_CONTROL_MEASUREMENT_CONFIGURATION] = value & 0xFE04; + tsc2101RefreshInterrupt(); + return; + + case TOUCH_DATA_X: + case TOUCH_DATA_Y: + case TOUCH_DATA_Z1: + case TOUCH_DATA_Z2: + case TOUCH_DATA_BAT: + case TOUCH_DATA_AUX1: + case TOUCH_DATA_AUX2: + case TOUCH_DATA_TEMP1: + case TOUCH_DATA_TEMP2: + //invalid write, ignore + return; + + case TOUCH_CONTROL_PROGRAMMABLE_DELAY: + //simple write, no actions needed + tsc2101Registers[combinedRegisterNumber] = value; + return; + + default: + if(page == 3) + debugLog("TSC2101 attempted to write buffer register:0x%02X, value:0x%04X\n", address, value); + debugLog("Unimplemented TSC2101 register write, page:0x%01X, address:0x%02X, value:0x%04X\n", page, address, value); + return; + } +} + +void tsc2101Reset(bool isBoot){ + tsc2101BufferReadPosition = 0; + tsc2101BufferWritePosition = 0; + tsc2101CurrentWord = 0x0000; + tsc2101CurrentWordBitsRemaining = 16; + tsc2101CurrentPage = 0; + tsc2101CurrentRegister = 0; + tsc2101CommandFinished = false; + tsc2101Read = false; + pxa260TimingCancelEvent(PXA260_TIMING_CALLBACK_TSC2101_SCAN); + + if(isBoot) + tsc2101ChipSelect = true; + + tsc2101ResetRegisters(); +} + +uint32_t tsc2101StateSize(void){ + +} + +void tsc2101SaveState(uint8_t* data){ + +} + +void tsc2101LoadState(uint8_t* data){ + +} + +void tsc2101SetChipSelect(bool value){ + if(value && !tsc2101ChipSelect){ + tsc2101CurrentWordBitsRemaining = 16; + tsc2101Read = false; + tsc2101CommandFinished = false; + tsc2101Registers[TOUCH_CONTROL_TSC_ADC] &= 0xC3FF;//TODO: treating this as "stop bit", may be wrong + pxa260TimingCancelEvent(PXA260_TIMING_CALLBACK_TSC2101_SCAN); + } + tsc2101ChipSelect = value; +} + +bool tsc2101ExchangeBit(bool bit){ + bool output = true;//TODO: SPI return value is usualy true but this is unverified + + if(tsc2101ChipSelect) + return true; + + if(!tsc2101Read){ + tsc2101CurrentWord <<= 1; + tsc2101CurrentWord |= bit; + } + else{ + output = !!(tsc2101CurrentWord & 0x8000); + tsc2101CurrentWord <<= 1; + } + tsc2101CurrentWordBitsRemaining--; + + if(tsc2101CurrentWordBitsRemaining == 0){ + if(!tsc2101CommandFinished){ + //write command word + tsc2101CurrentPage = tsc2101CurrentWord >> 11 & 0x000F; + tsc2101CurrentRegister = tsc2101CurrentWord >> 5 & 0x003F; + tsc2101Read = !!(tsc2101CurrentWord & 0x8000); + tsc2101CommandFinished = true; + if(tsc2101Read){ + //add first data word + tsc2101CurrentWord = tsc2101RegisterRead(tsc2101CurrentPage, tsc2101CurrentRegister); + tsc2101CurrentRegister++; + } + } + else if(!tsc2101Read){ + //write data word + //debugLog("TSC2101 should write now!\n"); + if(tsc2101CurrentRegister < 0x40){ + tsc2101RegisterWrite(tsc2101CurrentPage, tsc2101CurrentRegister, tsc2101CurrentWord); + tsc2101CurrentRegister++; + } + } + else{ + //read data word + if(tsc2101CurrentRegister < 0x40){ + tsc2101CurrentWord = tsc2101RegisterRead(tsc2101CurrentPage, tsc2101CurrentRegister); + tsc2101CurrentRegister++; + } + else{ + tsc2101CurrentWord = 0xFFFF; + } + } + + tsc2101CurrentWordBitsRemaining = 16; + } + + return output; +} + +void tsc2101RefreshInterrupt(void){ + debugLog("TSC2101 PINTDAV not fully implemented\n"); + + //check if PINTDAV is data or pen and data interrupt + if(tsc2101Registers[TOUCH_CONTROL_STATUS] >> 14 & 0x0003){ + if(tsc2101Registers[TOUCH_CONTROL_TEMPERATURE_MAX] & 0x1000 && ((tsc2101Registers[TOUCH_CONTROL_MEASUREMENT_CONFIGURATION] & 0x8000) ? tsc2101Registers[TOUCH_DATA_TEMP2] : tsc2101Registers[TOUCH_DATA_TEMP1]) >= (tsc2101Registers[TOUCH_CONTROL_TEMPERATURE_MAX] & 0xFFF)) + goto trigger; + + if(tsc2101Registers[TOUCH_CONTROL_TEMPERATURE_MIN] & 0x1000 && ((tsc2101Registers[TOUCH_CONTROL_MEASUREMENT_CONFIGURATION] & 0x8000) ? tsc2101Registers[TOUCH_DATA_TEMP2] : tsc2101Registers[TOUCH_DATA_TEMP1]) <= (tsc2101Registers[TOUCH_CONTROL_TEMPERATURE_MIN] & 0xFFF)) + goto trigger; + + if(tsc2101Registers[TOUCH_CONTROL_AUX1_MAX] & 0x1000 && tsc2101Registers[TOUCH_DATA_AUX1] >= (tsc2101Registers[TOUCH_CONTROL_AUX1_MAX] & 0xFFF)) + goto trigger; + + if(tsc2101Registers[TOUCH_CONTROL_AUX1_MIN] & 0x1000 && tsc2101Registers[TOUCH_DATA_AUX1] <= (tsc2101Registers[TOUCH_CONTROL_AUX1_MIN] & 0xFFF)) + goto trigger; + + if(tsc2101Registers[TOUCH_CONTROL_AUX2_MAX] & 0x1000 && tsc2101Registers[TOUCH_DATA_AUX2] >= (tsc2101Registers[TOUCH_CONTROL_AUX2_MAX] & 0xFFF)) + goto trigger; + + if(tsc2101Registers[TOUCH_CONTROL_AUX2_MIN] & 0x1000 && tsc2101Registers[TOUCH_DATA_AUX2] <= (tsc2101Registers[TOUCH_CONTROL_AUX2_MIN] & 0xFFF)) + goto trigger; + + if(tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] & 0x8000){ + //buffer mode, check if data is in buffer + if(tsc2101BufferFifoEntrys() >= ((tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] >> 11 & 0x0007) + 1) * 8) + goto trigger; + } + else{ + //register mode + if(tsc2101HasNewData) + goto trigger; + } + } + + //TODO: ignoring touch detect power down + //check PINTDAV is pen or pen and data interrupt and pen is down + if((tsc2101Registers[TOUCH_CONTROL_STATUS] >> 14 & 0x0003) != 0x0001) + if(palmInput.touchscreenTouched) + goto trigger; + + //TODO: set pin high + return; + + trigger: + //TODO: set pin low + return; +} + +void tsc2101Scan(void){ + bool keepScanning = false; + switch(tsc2101Registers[TOUCH_CONTROL_TSC_ADC] >> 10 & 0x000F){ case 0x0: //none @@ -184,6 +466,7 @@ static void tsc2101Scan(void){ tsc2101Registers[TOUCH_DATA_X] = tsc2101GetXValue(); tsc2101Registers[TOUCH_DATA_Y] = tsc2101GetYValue(); tsc2101HasNewData |= 1 << TOUCH_DATA_X | 1 << TOUCH_DATA_Y; + keepScanning = true; if(tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] & 0x8000){ tsc2101BufferFifoWrite(TOUCH_DATA_Y); @@ -198,6 +481,7 @@ static void tsc2101Scan(void){ tsc2101Registers[TOUCH_DATA_Z1] = tsc2101GetZ1Value(); tsc2101Registers[TOUCH_DATA_Z2] = tsc2101GetZ2Value(); tsc2101HasNewData |= 1 << TOUCH_DATA_X | 1 << TOUCH_DATA_Y | 1 << TOUCH_DATA_Z1 | 1 << TOUCH_DATA_Z2; + keepScanning = true; if(tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] & 0x8000){ tsc2101BufferFifoWrite(TOUCH_DATA_Y); @@ -267,6 +551,7 @@ static void tsc2101Scan(void){ case 0x9: //auto scan //TODO: implement + //keepScanning = true; debugLog("TSC2101 auto scan unimplemented\n"); break; @@ -285,6 +570,7 @@ static void tsc2101Scan(void){ tsc2101Registers[TOUCH_DATA_AUX1] = tsc2101GetAux1Value(); tsc2101Registers[TOUCH_DATA_AUX2] = tsc2101GetAux2Value(); tsc2101HasNewData |= 1 << TOUCH_DATA_BAT | 1 << TOUCH_DATA_AUX1 | 1 << TOUCH_DATA_AUX2; + keepScanning = true; if(tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] & 0x8000){ tsc2101BufferFifoWrite(TOUCH_DATA_BAT); @@ -308,274 +594,10 @@ static void tsc2101Scan(void){ } tsc2101RefreshInterrupt(); + + if(keepScanning) + pxa260TimingTriggerEvent(PXA260_TIMING_CALLBACK_TSC2101_SCAN, TSC2101_SCAN_DURATION); + else + tsc2101Registers[TOUCH_CONTROL_TSC_ADC] &= 0xC3FF; } -static void tsc2101ResetRegisters(void){ - tsc2101HasNewData = 0x0000; - - memset(tsc2101Registers, 0x00, sizeof(tsc2101Registers)); - - //TODO: need to add all the registers here - tsc2101Registers[TOUCH_CONTROL_STATUS] = 0x8000; - tsc2101Registers[TOUCH_CONTROL_REFERENCE] = 0x0002; - - tsc2101RefreshInterrupt(); -} - -static uint16_t tsc2101RegisterRead(uint8_t page, uint8_t address){ - uint8_t combinedRegisterNumber = TSC2101_REG_LOCATION(page, address); - - switch(combinedRegisterNumber){ - case TOUCH_CONTROL_TSC_ADC: - return tsc2101Registers[TOUCH_CONTROL_TSC_ADC] & 0x3FFF | palmInput.touchscreenTouched << 15 | 1 << 14/*TODO: this states the ADC is never busy*/; - - case TOUCH_CONTROL_STATUS: - //TODO: just always saying new data is available to avoid timing - debugLog("TSC2101 read status register\n"); - return tsc2101Registers[TOUCH_CONTROL_STATUS] | 0x0FDE; - - case TOUCH_CONTROL_BUFFER_MODE: - return tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] | (tsc2101BufferFifoEntrys() == 64) << 10 | (tsc2101BufferFifoEntrys() == 0) << 9; - - case TOUCH_CONTROL_RESET_CONTROL_REGISTER: - return 0xFFFF; - - //TOUCH_DATA_* registers are scaned, the values get copyed to the register when the result is generated - case TOUCH_DATA_X: - case TOUCH_DATA_Y: - case TOUCH_DATA_Z1: - case TOUCH_DATA_Z2: - case TOUCH_DATA_BAT: - case TOUCH_DATA_AUX1: - case TOUCH_DATA_AUX2: - case TOUCH_DATA_TEMP1: - case TOUCH_DATA_TEMP2: - tsc2101HasNewData &= ~(1 << combinedRegisterNumber); - return tsc2101Registers[combinedRegisterNumber]; - - default: - if(page == 3) - return tsc2101BufferFifoRead(); - debugLog("Unimplemented TSC2101 register read, page:0x%01X, address:0x%02X\n", page, address); - return 0x0000;//TODO: this may need to be 0xFFFF - } -} - -static void tsc2101RegisterWrite(uint8_t page, uint8_t address, uint16_t value){ - uint8_t combinedRegisterNumber = TSC2101_REG_LOCATION(page, address); - - switch(combinedRegisterNumber){ - case TOUCH_CONTROL_TSC_ADC: - tsc2101Registers[TOUCH_CONTROL_TSC_ADC] = value; - tsc2101Scan();//TODO: this should probably be on a timer - return; - - case TOUCH_CONTROL_REFERENCE: - //TODO: may need to divide the values by the referece voltage then multiply by 0xFFF - tsc2101Registers[TOUCH_CONTROL_REFERENCE] = value & 0x001F; - return; - - case TOUCH_CONTROL_RESET_CONTROL_REGISTER: - if(value == 0xBB00) - tsc2101ResetRegisters(); - return; - - case TOUCH_CONTROL_CONFIGURATION: - //TODO: TOUCH_CONTROL_CONFIGURATION SWPDTD bit - debugLog("TSC2101 config register writes not fully implemented\n"); - tsc2101Registers[TOUCH_CONTROL_CONFIGURATION] = value & 0x007F; - tsc2101RefreshInterrupt(); - return; - - case TOUCH_CONTROL_TEMPERATURE_MAX: - case TOUCH_CONTROL_TEMPERATURE_MIN: - case TOUCH_CONTROL_AUX1_MAX: - case TOUCH_CONTROL_AUX1_MIN: - case TOUCH_CONTROL_AUX2_MAX: - case TOUCH_CONTROL_AUX2_MIN: - tsc2101Registers[combinedRegisterNumber] = value & 0x1FFF; - tsc2101RefreshInterrupt(); - return; - - case TOUCH_CONTROL_MEASUREMENT_CONFIGURATION: - tsc2101Registers[TOUCH_CONTROL_MEASUREMENT_CONFIGURATION] = value & 0xFE04; - tsc2101RefreshInterrupt(); - return; - - case TOUCH_DATA_X: - case TOUCH_DATA_Y: - case TOUCH_DATA_Z1: - case TOUCH_DATA_Z2: - case TOUCH_DATA_BAT: - case TOUCH_DATA_AUX1: - case TOUCH_DATA_AUX2: - case TOUCH_DATA_TEMP1: - case TOUCH_DATA_TEMP2: - //invalid write, ignore - return; - - case TOUCH_CONTROL_PROGRAMMABLE_DELAY: - //simple write, no actions needed - tsc2101Registers[combinedRegisterNumber] = value; - return; - - default: - if(page == 3) - debugLog("TSC2101 attempted to write buffer register:0x%02X, value:0x%04X\n", address, value); - debugLog("Unimplemented TSC2101 register write, page:0x%01X, address:0x%02X, value:0x%04X\n", page, address, value); - return; - } -} - -void tsc2101Reset(bool isBoot){ - tsc2101BufferReadPosition = 0; - tsc2101BufferWritePosition = 0; - tsc2101CurrentWord = 0x0000; - tsc2101CurrentWordBitsRemaining = 16; - tsc2101CurrentPage = 0; - tsc2101CurrentRegister = 0; - tsc2101CommandFinished = false; - tsc2101Read = false; - - if(isBoot) - tsc2101ChipSelect = true; - - tsc2101ResetRegisters(); -} - -uint32_t tsc2101StateSize(void){ - -} - -void tsc2101SaveState(uint8_t* data){ - -} - -void tsc2101LoadState(uint8_t* data){ - -} - -void tsc2101SetChipSelect(bool value){ - //TODO: ADCSM references a "stop bit", this is likely when chip select goes high but I have no proof - //also dont know if the scan type value in the register is set to 0x0 - if(value && !tsc2101ChipSelect){ - tsc2101CurrentWordBitsRemaining = 16; - tsc2101Read = false; - tsc2101CommandFinished = false; - } - tsc2101ChipSelect = value; -} - -bool tsc2101ExchangeBit(bool bit){ - bool output = true;//TODO: SPI return value is usualy true but this is unverified - - if(tsc2101ChipSelect) - return true; - - if(!tsc2101Read){ - tsc2101CurrentWord <<= 1; - tsc2101CurrentWord |= bit; - } - else{ - output = !!(tsc2101CurrentWord & 0x8000); - tsc2101CurrentWord <<= 1; - } - tsc2101CurrentWordBitsRemaining--; - - if(tsc2101CurrentWordBitsRemaining == 0){ - if(!tsc2101CommandFinished){ - //write command word - tsc2101CurrentPage = tsc2101CurrentWord >> 11 & 0x000F; - tsc2101CurrentRegister = tsc2101CurrentWord >> 5 & 0x003F; - tsc2101Read = !!(tsc2101CurrentWord & 0x8000); - tsc2101CommandFinished = true; - if(tsc2101Read){ - //add first data word - tsc2101CurrentWord = tsc2101RegisterRead(tsc2101CurrentPage, tsc2101CurrentRegister); - tsc2101CurrentRegister++; - } - } - else if(!tsc2101Read){ - //write data word - //debugLog("TSC2101 should write now!\n"); - if(tsc2101CurrentRegister < 0x40){ - tsc2101RegisterWrite(tsc2101CurrentPage, tsc2101CurrentRegister, tsc2101CurrentWord); - tsc2101CurrentRegister++; - } - } - else{ - //read data word - if(tsc2101CurrentRegister < 0x40){ - tsc2101CurrentWord = tsc2101RegisterRead(tsc2101CurrentPage, tsc2101CurrentRegister); - tsc2101CurrentRegister++; - } - else{ - tsc2101CurrentWord = 0xFFFF; - } - } - - tsc2101CurrentWordBitsRemaining = 16; - } - - return output; -} - -void tsc2101RefreshInterrupt(void){ - debugLog("TSC2101 PINTDAV not fully implemented\n"); - - //check if PINTDAV is data or pen and data interrupt - if(tsc2101Registers[TOUCH_CONTROL_STATUS] >> 14 & 0x0003){ - uint16_t aux1 = tsc2101Registers[TOUCH_DATA_AUX1]; - uint16_t aux2 = tsc2101Registers[TOUCH_DATA_AUX2]; - uint16_t temp1 = tsc2101Registers[TOUCH_DATA_TEMP1]; - uint16_t temp2 = tsc2101Registers[TOUCH_DATA_TEMP2]; - bool useTemp2 = !!(tsc2101Registers[TOUCH_CONTROL_MEASUREMENT_CONFIGURATION] & 0x8000); - uint16_t temperatureMax = tsc2101Registers[TOUCH_CONTROL_TEMPERATURE_MAX]; - uint16_t temperatureMin = tsc2101Registers[TOUCH_CONTROL_TEMPERATURE_MIN]; - uint16_t aux1Max = tsc2101Registers[TOUCH_CONTROL_AUX1_MAX]; - uint16_t aux1Min = tsc2101Registers[TOUCH_CONTROL_AUX1_MIN]; - uint16_t aux2Max = tsc2101Registers[TOUCH_CONTROL_AUX2_MAX]; - uint16_t aux2Min = tsc2101Registers[TOUCH_CONTROL_AUX2_MIN]; - - if(temperatureMax & 0x1000 && (useTemp2 ? temp2 : temp1) >= (temperatureMax & 0xFFF)) - goto trigger; - - if(temperatureMin & 0x1000 && (useTemp2 ? temp2 : temp1) <= (temperatureMin & 0xFFF)) - goto trigger; - - if(aux1Max & 0x1000 && aux1 >= (aux1Max & 0xFFF)) - goto trigger; - - if(aux1Min & 0x1000 && aux1 <= (aux1Min & 0xFFF)) - goto trigger; - - if(aux2Max & 0x1000 && aux2 >= (aux2Max & 0xFFF)) - goto trigger; - - if(aux2Min & 0x1000 && aux2 <= (aux2Min & 0xFFF)) - goto trigger; - - if(tsc2101Registers[TOUCH_CONTROL_BUFFER_MODE] & 0x8000){ - //buffer mode, check if data is in buffer - if(tsc2101BufferFifoEntrys() > 0) - goto trigger; - } - else{ - //register mode - if(tsc2101HasNewData) - goto trigger; - } - } - - //check PINTDAV is pen or pen and data interrupt and pen is down - if((tsc2101Registers[TOUCH_CONTROL_STATUS] >> 14 & 0x0003) != 0x0001) - if(palmInput.touchscreenTouched) - goto trigger; - - //TODO: set pin high - return; - - trigger: - //TODO: set pin low - return; -} diff --git a/src/tsc2101.h b/src/tsc2101.h index 64eba3e..74ca887 100644 --- a/src/tsc2101.h +++ b/src/tsc2101.h @@ -14,4 +14,6 @@ bool tsc2101ExchangeBit(bool bit); void tsc2101RefreshInterrupt(void);//called after touchscreen update to flush the values //TODO: this chip seems to do audio output, need to add a 16bit optimized transfer function +void tsc2101Scan(void); + #endif