diff --git a/hal/m258ke/parallel_bus.c b/hal/m258ke/parallel_bus.c index 5c6d095..721161c 100644 --- a/hal/m258ke/parallel_bus.c +++ b/hal/m258ke/parallel_bus.c @@ -73,15 +73,24 @@ void ParallelBus_Init(void) // Configure all address lines as outputs, outputting address 0 ParallelBus_SetAddressDir((1UL << (PARALLEL_BUS_HIGHEST_ADDRESS_LINE + 1)) - 1); ParallelBus_SetAddress(0); + ParallelBus_SetAddressPullups(0); + ParallelBus_SetAddressPulldowns(0); // Set all data lines to pulled-up inputs ParallelBus_SetDataAllInput(); ParallelBus_SetDataPullups(0xFFFFFFFFUL); + ParallelBus_SetDataPulldowns(0); // Control lines ParallelBus_SetCSDir(true); + ParallelBus_SetCSPullup(false); + ParallelBus_SetCSPulldown(false); ParallelBus_SetOEDir(true); + ParallelBus_SetOEPullup(false); + ParallelBus_SetOEPulldown(false); ParallelBus_SetWEDir(true); + ParallelBus_SetWEPullup(false); + ParallelBus_SetWEPulldown(false); // Default to only CS asserted DeassertControl(FLASH_WE_PIN); @@ -328,12 +337,13 @@ void ParallelBus_SetAddressPullups(uint32_t pullups) // For efficiency, we talk directly to the registers in this function, // rather than going through the GPIO class. - // There are actually 2 bits per pin. We want to write 00 if disabled, - // 01 if enabled. So we need to interleave a zero in between each bit - // to match the register layout. + // There are actually 2 bits per pin. The lowest bit is the pullup control. + // The highest bit is the pulldown control, which we want to leave alone. + // We want to write 0 to pullup if disabled, 1 if enabled. So we need to + // interleave a zero in between each bit to avoid touching the pulldowns. - const uint32_t regMaskA = 0xFFFFFFUL; - const uint32_t regMaskC = 0x3FFFFUL; + const uint32_t regMaskA = 0x555555UL; + const uint32_t regMaskC = 0x15555UL; const uint32_t regA = InterleaveZeros(addrA); const uint32_t regC = InterleaveZeros(addrC); @@ -348,6 +358,45 @@ void ParallelBus_SetAddressPullups(uint32_t pullups) PC->PUSEL = tmpC; } +/** Sets which pins on the 21-bit address bus should be pulled down (if inputs) + * + * @param pulldowns Mask of pins that should be pulldowns. + * + * This would typically only be used for testing. Under normal operation, the + * address bus will be outputting, so the pulldowns are irrelevant. + */ +void ParallelBus_SetAddressPulldowns(uint32_t pulldowns) +{ + const uint32_t addrMaskA = 0xFFFUL; + const uint32_t addrMaskC = 0x1FFUL; + + const uint32_t addrA = pulldowns & addrMaskA; + const uint32_t addrC = (pulldowns >> 12) & addrMaskC; + + // For efficiency, we talk directly to the registers in this function, + // rather than going through the GPIO class. + + // There are actually 2 bits per pin. The lowest bit is the pullup control, + // which we want to leave alone. The highest bit is the pulldown control. + // We want to write 0 to pulldown if disabled, 1 if enabled. So we need to + // interleave a zero in between each bit to avoid touching the pullups. + + const uint32_t regMaskA = 0xAAAAAAUL; + const uint32_t regMaskC = 0x2AAAAUL; + + const uint32_t regA = InterleaveZeros(addrA) << 1; + const uint32_t regC = InterleaveZeros(addrC) << 1; + + uint32_t tmpA = PA->PUSEL; + uint32_t tmpC = PC->PUSEL; + tmpA &= ~regMaskA; + tmpA |= regA; + tmpC &= ~regMaskC; + tmpC |= regC; + PA->PUSEL = tmpA; + PC->PUSEL = tmpC; +} + /** Sets which pins on the 32-bit data bus should be pulled up (if inputs) * * @param pullups Mask of pins that should be pullups. @@ -367,15 +416,63 @@ void ParallelBus_SetDataPullups(uint32_t pullups) // For efficiency, we talk directly to the registers in this function, // rather than going through the GPIO class. - // There are actually 2 bits per pin. We want to write 00 if input, - // 01 if output. So we need to interleave a zero in between each bit - // to match the register layout. + // There are actually 2 bits per pin. The lowest bit is the pullup control. + // The highest bit is the pulldown control, which we want to leave alone. + // We want to write 0 to pullup if disabled, 1 if enabled. So we need to + // interleave a zero in between each bit to avoid touching the pulldowns. + + const uint32_t regMask = 0x55555555UL; const uint32_t regB = InterleaveZeros(dataB); const uint32_t regE = InterleaveZeros(dataE); - PB->PUSEL = regB; - PE->PUSEL = regE; + uint32_t tmpB = PB->PUSEL; + uint32_t tmpE = PE->PUSEL; + tmpB &= ~regMask; + tmpB |= regB; + tmpE &= ~regMask; + tmpE |= regE; + PB->PUSEL = tmpB; + PE->PUSEL = tmpE; +} + +/** Sets which pins on the 32-bit data bus should be pulled down (if inputs) + * + * @param pulldowns Mask of pins that should be pulldowns. + * + * Typically these will be enabled in order to provide a default value if a + * chip isn't responding properly. Sometimes it's useful to customize it during + * testing though. + */ +void ParallelBus_SetDataPulldowns(uint32_t pulldowns) +{ + const uint32_t dataMaskB = 0xFFFFUL; + const uint32_t dataMaskE = 0xFFFFUL; + + const uint32_t dataB = (pulldowns >> 16) & dataMaskB; + const uint32_t dataE = (pulldowns >> 0) & dataMaskE; + + // For efficiency, we talk directly to the registers in this function, + // rather than going through the GPIO class. + + // There are actually 2 bits per pin. The lowest bit is the pullup control, + // which we want to leave alone. The highest bit is the pulldown control. + // We want to write 0 to pulldown if disabled, 1 if enabled. So we need to + // interleave a zero in between each bit to avoid touching the pullups. + + const uint32_t regMask = 0xAAAAAAAAUL; + + const uint32_t regB = InterleaveZeros(dataB) << 1; + const uint32_t regE = InterleaveZeros(dataE) << 1; + + uint32_t tmpB = PB->PUSEL; + uint32_t tmpE = PE->PUSEL; + tmpB &= ~regMask; + tmpB |= regB; + tmpE &= ~regMask; + tmpE |= regE; + PB->PUSEL = tmpB; + PE->PUSEL = tmpE; } /** Sets whether the CS pin is pulled up, if it's an input. @@ -390,6 +487,18 @@ void ParallelBus_SetCSPullup(bool pullup) GPIO_SetPullup(flashCSPin, pullup); } +/** Sets whether the CS pin is pulled down, if it's an input. + * + * @param pulldown True if the CS pin should be pulled down, false if not + * + * This would typically only be used for testing. Under normal operation, this + * pin will be set as an output, so the pulldown state is irrelevant. + */ +void ParallelBus_SetCSPulldown(bool pulldown) +{ + GPIO_SetPulldown(flashCSPin, pulldown); +} + /** Sets whether the OE pin is pulled up, if it's an input. * * @param pullup True if the OE pin should be pulled up, false if not @@ -402,6 +511,18 @@ void ParallelBus_SetOEPullup(bool pullup) GPIO_SetPullup(flashOEPin, pullup); } +/** Sets whether the OE pin is pulled down, if it's an input. + * + * @param pulldown True if the OE pin should be pulled down, false if not + * + * This would typically only be used for testing. Under normal operation, this + * pin will be set as an output, so the pulldown state is irrelevant. + */ +void ParallelBus_SetOEPulldown(bool pulldown) +{ + GPIO_SetPulldown(flashOEPin, pulldown); +} + /** Sets whether the WE pin is pulled up, if it's an input. * * @param pullup True if the WE pin should be pulled up, false if not @@ -414,6 +535,18 @@ void ParallelBus_SetWEPullup(bool pullup) GPIO_SetPullup(flashWEPin, pullup); } +/** Sets whether the WE pin is pulled down, if it's an input. + * + * @param pulldown True if the WE pin should be pulled down, false if not + * + * This would typically only be used for testing. Under normal operation, this + * pin will be set as an output, so the pulldown state is irrelevant. + */ +void ParallelBus_SetWEPulldown(bool pulldown) +{ + GPIO_SetPulldown(flashWEPin, pulldown); +} + /** Reads the current data on the address bus. * * @return The address bus readback