X-Git-Url: http://git.linex4red.de/pub/USBasp.git/blobdiff_plain/bb3879331211a19c3adc3927cac870cc7e36b775..24f730fce3f2022762011d795c3feada5ef874b3:/Projects/AVRISP/Lib/PDITarget.c?ds=sidebyside diff --git a/Projects/AVRISP/Lib/PDITarget.c b/Projects/AVRISP/Lib/PDITarget.c index c774fdab8..29bb33985 100644 --- a/Projects/AVRISP/Lib/PDITarget.c +++ b/Projects/AVRISP/Lib/PDITarget.c @@ -39,14 +39,14 @@ #if defined(ENABLE_PDI_PROTOCOL) || defined(__DOXYGEN__) /** Flag to indicate if the USART is currently in Tx or Rx mode. */ -volatile bool IsSending; +volatile bool IsSending; #if !defined(PDI_VIA_HARDWARE_USART) /** Software USART raw frame bits for transmission/reception. */ -volatile uint16_t SoftUSART_Data; +volatile uint16_t SoftUSART_Data; -/** Bits remaining to be sent or received via the software USART. */ -volatile uint8_t SoftUSART_BitCount; +/** Bits remaining to be sent or received via the software USART - set as a GPIOR for speed. */ +#define SoftUSART_BitCount GPIOR2 /** ISR to manage the software USART when bit-banged USART mode is selected. */ @@ -59,27 +59,36 @@ ISR(TIMER1_COMPA_vect, ISR_BLOCK) if (!(SoftUSART_BitCount)) return; - /* Check to see if the current clock state is on the rising or falling edge */ - bool IsRisingEdge = (BITBANG_PDICLOCK_PORT & BITBANG_PDICLOCK_MASK); - - if (IsSending && !IsRisingEdge) + /* Check to see if we are at a rising or falling edge of the clock */ + if (BITBANG_PDICLOCK_PORT & BITBANG_PDICLOCK_MASK) { - if (SoftUSART_Data & 0x01) - BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK; - else - BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK; + /* If at rising clock edge and we are in send mode, abort */ + if (IsSending) + return; + + /* Wait for the start bit when receiving */ + if ((SoftUSART_BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)) + return; + + /* Shift in the bit one less than the frame size in position, so that the start bit will eventually + * be discarded leaving the data to be byte-aligned for quick access */ + if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK) + SoftUSART_Data |= (1 << (BITS_IN_FRAME - 1)); SoftUSART_Data >>= 1; SoftUSART_BitCount--; } - else if (!IsSending && IsRisingEdge) + else { - /* Wait for the start bit when receiving */ - if ((SoftUSART_BitCount == BITS_IN_FRAME) && (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK)) + /* If at falling clock edge and we are in receive mode, abort */ + if (!IsSending) return; - - if (BITBANG_PDIDATA_PIN & BITBANG_PDIDATA_MASK) - SoftUSART_Data |= (1 << BITS_IN_FRAME); + + /* Set the data line to the next bit value */ + if (SoftUSART_Data & 0x01) + BITBANG_PDIDATA_PORT |= BITBANG_PDIDATA_MASK; + else + BITBANG_PDIDATA_PORT &= ~BITBANG_PDIDATA_MASK; SoftUSART_Data >>= 1; SoftUSART_BitCount--; @@ -102,7 +111,7 @@ void PDITarget_EnableTargetPDI(void) /* Set up the synchronous USART for XMEGA communications - 8 data bits, even parity, 2 stop bits */ - UBRR1 = 10; + UBRR1 = (F_CPU / 1000000UL); UCSR1B = (1 << TXEN1); UCSR1C = (1 << UMSEL10) | (1 << UPM11) | (1 << USBS1) | (1 << UCSZ11) | (1 << UCSZ10) | (1 << UCPOL1); @@ -120,7 +129,7 @@ void PDITarget_EnableTargetPDI(void) asm volatile ("NOP"::); /* Fire timer compare ISR every 100 cycles to manage the software USART */ - OCR1A = 100; + OCR1A = 80; TCCR1B = (1 << WGM12) | (1 << CS10); TIMSK1 = (1 << OCIE1A); @@ -158,7 +167,7 @@ void PDITarget_DisableTargetPDI(void) * * \param[in] Byte Byte to send through the USART */ -void PDITarget_SendByte(uint8_t Byte) +void PDITarget_SendByte(const uint8_t Byte) { #if defined(PDI_VIA_HARDWARE_USART) /* Switch to Tx mode if currently in Rx mode */ @@ -167,15 +176,16 @@ void PDITarget_SendByte(uint8_t Byte) PORTD |= (1 << 3); DDRD |= (1 << 3); - UCSR1B &= ~(1 << RXEN1); UCSR1B |= (1 << TXEN1); + UCSR1B &= ~(1 << RXEN1); IsSending = true; } /* Wait until there is space in the hardware Tx buffer before writing */ while (!(UCSR1A & (1 << UDRE1))); - UDR1 = Byte; + UCSR1A |= (1 << TXC1); + UDR1 = Byte; #else /* Switch to Tx mode if currently in Rx mode */ if (!(IsSending)) @@ -186,20 +196,22 @@ void PDITarget_SendByte(uint8_t Byte) IsSending = true; } - bool EvenParityBit = false; - uint8_t ParityData = Byte; + /* Calculate the new USART frame data here while while we wait for a previous byte (if any) to finish sending */ + uint16_t NewUSARTData = ((1 << 11) | (1 << 10) | (0 << 9) | ((uint16_t)Byte << 1) | (0 << 0)); - /* Compute Even parity bit */ - for (uint8_t i = 0; i < 8; i++) + /* Compute Even parity - while a bit is still set, chop off lowest bit and toggle parity bit */ + uint8_t ParityData = Byte; + while (ParityData) { - EvenParityBit ^= ParityData & 0x01; - ParityData >>= 1; + NewUSARTData ^= (1 << 9); + ParityData &= (ParityData - 1); } + /* Wait until transmitter is idle before writing new data */ while (SoftUSART_BitCount); /* Data shifted out LSB first, START DATA PARITY STOP STOP */ - SoftUSART_Data = ((uint16_t)EvenParityBit << 9) | ((uint16_t)Byte << 1) | (1 << 10) | (1 << 11); + SoftUSART_Data = NewUSARTData; SoftUSART_BitCount = BITS_IN_FRAME; #endif } @@ -245,8 +257,8 @@ uint8_t PDITarget_ReceiveByte(void) SoftUSART_BitCount = BITS_IN_FRAME; while (SoftUSART_BitCount); - /* Throw away the start, parity and stop bits to leave only the data */ - return (uint8_t)(SoftUSART_Data >> 1); + /* Throw away the parity and stop bits to leave only the data (start bit is already discarded) */ + return (uint8_t)SoftUSART_Data; #endif } @@ -267,7 +279,7 @@ void PDITarget_SendBreak(void) } /* Need to do nothing for a full frame to send a BREAK */ - for (uint8_t i = 0; i <= BITS_IN_FRAME; i++) + for (uint8_t i = 0; i < BITS_IN_FRAME; i++) { /* Wait for a full cycle of the clock */ while (PIND & (1 << 5)); @@ -299,14 +311,23 @@ void PDITarget_SendBreak(void) bool PDITarget_WaitWhileNVMBusBusy(void) { TCNT0 = 0; - + TIFR0 = (1 << OCF1A); + + uint8_t TimeoutMS = PDI_NVM_TIMEOUT_MS; + /* Poll the STATUS register to check to see if NVM access has been enabled */ - while (TCNT0 < PDI_NVM_TIMEOUT_MS) + while (TimeoutMS) { /* Send the LDCS command to read the PDI STATUS register to see the NVM bus is active */ PDITarget_SendByte(PDI_CMD_LDCS | PDI_STATUS_REG); if (PDITarget_ReceiveByte() & PDI_STATUS_NVM) return true; + + if (TIFR0 & (1 << OCF1A)) + { + TIFR0 = (1 << OCF1A); + TimeoutMS--; + } } return false;