Refactored AVR8 target pin state manipulation - removed unnecessary register accesses when setting pin states
This commit is contained in:
@@ -452,23 +452,23 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
|
|
||||||
auto pinState = TargetPinState();
|
auto pinState = TargetPinState();
|
||||||
|
|
||||||
if (pad.ddrSetAddress.has_value()) {
|
if (pad.gpioDdrAddress.has_value()) {
|
||||||
auto dataDirectionRegisterValue = readMemoryBitset(pad.ddrSetAddress.value());
|
const auto ddrValue = readMemoryBitset(pad.gpioDdrAddress.value());
|
||||||
pinState.ioDirection = dataDirectionRegisterValue.test(pad.gpioPinNumber.value()) ?
|
|
||||||
|
pinState.ioDirection = ddrValue.test(pad.gpioPinNumber.value()) ?
|
||||||
TargetPinState::IoDirection::OUTPUT : TargetPinState::IoDirection::INPUT;
|
TargetPinState::IoDirection::OUTPUT : TargetPinState::IoDirection::INPUT;
|
||||||
|
|
||||||
if (pinState.ioDirection == TargetPinState::IoDirection::OUTPUT
|
if (pinState.ioDirection == TargetPinState::IoDirection::OUTPUT
|
||||||
&& pad.gpioPortSetAddress.has_value()
|
&& pad.gpioPortAddress.has_value()
|
||||||
) {
|
) {
|
||||||
auto portRegisterValue = readMemoryBitset(pad.gpioPortSetAddress.value());
|
const auto portRegisterValueBitset = readMemoryBitset(pad.gpioPortAddress.value());
|
||||||
pinState.ioState = portRegisterValue.test(pad.gpioPinNumber.value()) ?
|
pinState.ioState = portRegisterValueBitset.test(pad.gpioPinNumber.value()) ?
|
||||||
TargetPinState::IoState::HIGH : TargetPinState::IoState::LOW;
|
TargetPinState::IoState::HIGH : TargetPinState::IoState::LOW;
|
||||||
|
|
||||||
} else if (pinState.ioDirection == TargetPinState::IoDirection::INPUT
|
} else if (pinState.ioDirection == TargetPinState::IoDirection::INPUT
|
||||||
&& pad.gpioPortInputAddress.has_value()
|
&& pad.gpioPortInputAddress.has_value()
|
||||||
) {
|
) {
|
||||||
auto portInputRegisterValue = readMemoryBitset(pad.gpioPortInputAddress.value());
|
const auto portInputRegisterValue = readMemoryBitset(pad.gpioPortInputAddress.value());
|
||||||
auto h = portInputRegisterValue.to_string();
|
|
||||||
pinState.ioState = portInputRegisterValue.test(pad.gpioPinNumber.value()) ?
|
pinState.ioState = portInputRegisterValue.test(pad.gpioPinNumber.value()) ?
|
||||||
TargetPinState::IoState::HIGH : TargetPinState::IoState::LOW;
|
TargetPinState::IoState::HIGH : TargetPinState::IoState::LOW;
|
||||||
}
|
}
|
||||||
@@ -495,8 +495,8 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
throw Exception("Missing IO direction state");
|
throw Exception("Missing IO direction state");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& variant = this->targetVariantsById.at(variantId);
|
const auto& variant = this->targetVariantsById.at(variantId);
|
||||||
auto& padDescriptor = this->padDescriptorsByName.at(pinDescriptor.padName);
|
const auto& padDescriptor = this->padDescriptorsByName.at(pinDescriptor.padName);
|
||||||
auto ioState = state.ioState;
|
auto ioState = state.ioState;
|
||||||
|
|
||||||
if (state.ioDirection == TargetPinState::IoDirection::INPUT) {
|
if (state.ioDirection == TargetPinState::IoDirection::INPUT) {
|
||||||
@@ -505,116 +505,53 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!padDescriptor.ddrSetAddress.has_value()
|
!padDescriptor.gpioDdrAddress.has_value()
|
||||||
|| !padDescriptor.gpioPortSetAddress.has_value()
|
|| !padDescriptor.gpioPortAddress.has_value()
|
||||||
|| !padDescriptor.gpioPinNumber.has_value()
|
|| !padDescriptor.gpioPinNumber.has_value()
|
||||||
) {
|
) {
|
||||||
throw Exception("Inadequate pad descriptor");
|
throw Exception("Inadequate pad descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pinNumber = padDescriptor.gpioPinNumber.value();
|
const auto pinNumber = padDescriptor.gpioPinNumber.value();
|
||||||
auto ddrSetAddress = padDescriptor.ddrSetAddress.value();
|
const auto ddrAddress = padDescriptor.gpioDdrAddress.value();
|
||||||
auto ddrSetValue = this->readMemory(TargetMemoryType::RAM, ddrSetAddress, 1);
|
const auto ddrValue = this->readMemory(TargetMemoryType::RAM, ddrAddress, 1);
|
||||||
|
|
||||||
if (ddrSetValue.empty()) {
|
if (ddrValue.empty()) {
|
||||||
throw Exception("Failed to read DDSR value");
|
throw Exception("Failed to read DDR value");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ddrSetBitset = std::bitset<std::numeric_limits<unsigned char>::digits>(ddrSetValue.front());
|
auto ddrValueBitset = std::bitset<std::numeric_limits<unsigned char>::digits>(ddrValue.front());
|
||||||
if (ddrSetBitset.test(pinNumber) != (state.ioDirection == TargetPinState::IoDirection::OUTPUT)) {
|
if (ddrValueBitset.test(pinNumber) != (state.ioDirection == TargetPinState::IoDirection::OUTPUT)) {
|
||||||
// DDR needs updating
|
// DDR needs updating
|
||||||
ddrSetBitset.set(pinNumber, (state.ioDirection == TargetPinState::IoDirection::OUTPUT));
|
ddrValueBitset.set(pinNumber, (state.ioDirection == TargetPinState::IoDirection::OUTPUT));
|
||||||
|
|
||||||
this->writeMemory(
|
this->writeMemory(
|
||||||
TargetMemoryType::RAM,
|
TargetMemoryType::RAM,
|
||||||
ddrSetAddress,
|
ddrAddress,
|
||||||
{static_cast<unsigned char>(ddrSetBitset.to_ulong())}
|
{static_cast<unsigned char>(ddrValueBitset.to_ulong())}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (padDescriptor.ddrClearAddress.has_value() && padDescriptor.ddrClearAddress != ddrSetAddress) {
|
|
||||||
// We also need to ensure the data direction clear register value is correct
|
|
||||||
auto ddrClearAddress = padDescriptor.ddrClearAddress.value();
|
|
||||||
auto ddrClearValue = this->readMemory(TargetMemoryType::RAM, ddrClearAddress, 1);
|
|
||||||
|
|
||||||
if (ddrClearValue.empty()) {
|
|
||||||
throw Exception("Failed to read DDCR value");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ddrClearBitset = std::bitset<std::numeric_limits<unsigned char>::digits>(ddrClearValue.front());
|
|
||||||
if (ddrClearBitset.test(pinNumber) == (state.ioDirection == TargetPinState::IoDirection::INPUT)) {
|
|
||||||
ddrClearBitset.set(pinNumber, (state.ioDirection == TargetPinState::IoDirection::INPUT));
|
|
||||||
|
|
||||||
this->writeMemory(
|
|
||||||
TargetMemoryType::RAM,
|
|
||||||
ddrClearAddress,
|
|
||||||
{static_cast<unsigned char>(ddrClearBitset.to_ulong())}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioState.has_value()) {
|
if (ioState.has_value()) {
|
||||||
auto portSetAddress = padDescriptor.gpioPortSetAddress.value();
|
const auto portRegisterAddress = padDescriptor.gpioPortAddress.value();
|
||||||
|
const auto portRegisterValue = this->readMemory(TargetMemoryType::RAM, portRegisterAddress, 1);
|
||||||
|
|
||||||
if (ioState == TargetPinState::IoState::HIGH
|
if (portRegisterValue.empty()) {
|
||||||
|| !padDescriptor.gpioPortClearAddress.has_value()
|
|
||||||
|| padDescriptor.gpioPortClearAddress == portSetAddress
|
|
||||||
) {
|
|
||||||
if (padDescriptor.gpioPortClearAddress != portSetAddress) {
|
|
||||||
/*
|
|
||||||
* We don't need to read the SET register if the SET and CLEAR operations are performed via
|
|
||||||
* different registers.
|
|
||||||
*
|
|
||||||
* Instead, we can just set the appropriate bit against the SET register.
|
|
||||||
*/
|
|
||||||
this->writeMemory(
|
|
||||||
TargetMemoryType::RAM,
|
|
||||||
portSetAddress,
|
|
||||||
{static_cast<unsigned char>(0x01 << pinNumber)}
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
auto portSetRegisterValue = this->readMemory(
|
|
||||||
TargetMemoryType::RAM,
|
|
||||||
portSetAddress,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
|
|
||||||
if (portSetRegisterValue.empty()) {
|
|
||||||
throw Exception("Failed to read PORT register value");
|
throw Exception("Failed to read PORT register value");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto portSetBitset = std::bitset<std::numeric_limits<unsigned char>::digits>(
|
auto portRegisterValueBitset = std::bitset<std::numeric_limits<unsigned char>::digits>(
|
||||||
portSetRegisterValue.front()
|
portRegisterValue.front()
|
||||||
);
|
);
|
||||||
if (portSetBitset.test(pinNumber) != (ioState == TargetPinState::IoState::HIGH)) {
|
|
||||||
|
if (portRegisterValueBitset.test(pinNumber) != (ioState == TargetPinState::IoState::HIGH)) {
|
||||||
// PORT set register needs updating
|
// PORT set register needs updating
|
||||||
portSetBitset.set(pinNumber, (ioState == TargetPinState::IoState::HIGH));
|
portRegisterValueBitset.set(pinNumber, (ioState == TargetPinState::IoState::HIGH));
|
||||||
|
|
||||||
this->writeMemory(
|
this->writeMemory(
|
||||||
TargetMemoryType::RAM,
|
TargetMemoryType::RAM,
|
||||||
portSetAddress,
|
portRegisterAddress,
|
||||||
{static_cast<unsigned char>(portSetBitset.to_ulong())}
|
{static_cast<unsigned char>(portRegisterValueBitset.to_ulong())}
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We only need to update the PORT clear register if the IO state was set to LOW, and the clear register is
|
|
||||||
* not the same register as the set register.
|
|
||||||
*/
|
|
||||||
if (ioState == TargetPinState::IoState::LOW
|
|
||||||
&& padDescriptor.gpioPortClearAddress.has_value()
|
|
||||||
&& padDescriptor.gpioPortClearAddress != portSetAddress
|
|
||||||
) {
|
|
||||||
// We also need to ensure the PORT clear register value is correct
|
|
||||||
auto portClearAddress = padDescriptor.gpioPortClearAddress.value();
|
|
||||||
|
|
||||||
this->writeMemory(
|
|
||||||
TargetMemoryType::RAM,
|
|
||||||
portClearAddress,
|
|
||||||
{static_cast<unsigned char>(0x01 << pinNumber)}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,22 +21,8 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit
|
|||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
std::optional<std::uint8_t> gpioPinNumber;
|
std::optional<std::uint8_t> gpioPinNumber;
|
||||||
|
std::optional<std::uint16_t> gpioPortAddress;
|
||||||
/**
|
|
||||||
* AVR8 GPIO pins can be manipulated by writing to an IO register address. The gpioPortAddress member
|
|
||||||
* holds this address.
|
|
||||||
*/
|
|
||||||
std::optional<std::uint16_t> gpioPortSetAddress;
|
|
||||||
std::optional<std::uint16_t> gpioPortInputAddress;
|
std::optional<std::uint16_t> gpioPortInputAddress;
|
||||||
|
std::optional<std::uint16_t> gpioDdrAddress;
|
||||||
std::optional<std::uint16_t> gpioPortClearAddress;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The data direction of a pin is configured via a data direction register (DDR), which, like the
|
|
||||||
* gpioPortSetAddress, is an IO register.
|
|
||||||
*/
|
|
||||||
std::optional<std::uint16_t> ddrSetAddress;
|
|
||||||
|
|
||||||
std::optional<std::uint16_t> ddrClearAddress;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,8 +441,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
|||||||
for (const auto& [registerName, portRegister] : registerGroup.registersMappedByName) {
|
for (const auto& [registerName, portRegister] : registerGroup.registersMappedByName) {
|
||||||
if (registerName.find("port") == 0) {
|
if (registerName.find("port") == 0) {
|
||||||
// This is the data register for the port
|
// This is the data register for the port
|
||||||
padDescriptor.gpioPortSetAddress = portRegister.offset;
|
padDescriptor.gpioPortAddress = portRegister.offset;
|
||||||
padDescriptor.gpioPortClearAddress = portRegister.offset;
|
|
||||||
|
|
||||||
} else if (registerName.find("pin") == 0) {
|
} else if (registerName.find("pin") == 0) {
|
||||||
// This is the input data register for the port
|
// This is the input data register for the port
|
||||||
@@ -450,8 +449,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
|||||||
|
|
||||||
} else if (registerName.find("ddr") == 0) {
|
} else if (registerName.find("ddr") == 0) {
|
||||||
// This is the data direction register for the port
|
// This is the data direction register for the port
|
||||||
padDescriptor.ddrSetAddress = portRegister.offset;
|
padDescriptor.gpioDdrAddress = portRegister.offset;
|
||||||
padDescriptor.ddrClearAddress = portRegister.offset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,46 +458,31 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
|||||||
auto registerGroup = portModule->registerGroupsMappedByName.find("port")->second;
|
auto registerGroup = portModule->registerGroupsMappedByName.find("port")->second;
|
||||||
|
|
||||||
for (const auto& [registerName, portRegister] : registerGroup.registersMappedByName) {
|
for (const auto& [registerName, portRegister] : registerGroup.registersMappedByName) {
|
||||||
if (registerName.find("outset") == 0) {
|
if (registerName == "out") {
|
||||||
// Include the port register offset
|
// Include the port register offset
|
||||||
padDescriptor.gpioPortSetAddress = (portPeripheralRegisterGroup.has_value()
|
padDescriptor.gpioPortAddress = (
|
||||||
&& portPeripheralRegisterGroup->offset.has_value()) ?
|
portPeripheralRegisterGroup.has_value()
|
||||||
portPeripheralRegisterGroup->offset.value_or(0) : 0;
|
&& portPeripheralRegisterGroup->offset.has_value()
|
||||||
|
)
|
||||||
|
? portPeripheralRegisterGroup->offset.value_or(0) + portRegister.offset
|
||||||
|
: 0 + portRegister.offset;
|
||||||
|
|
||||||
padDescriptor.gpioPortSetAddress = padDescriptor.gpioPortSetAddress.value()
|
|
||||||
+ portRegister.offset;
|
|
||||||
|
|
||||||
} else if (registerName.find("outclr") == 0) {
|
} else if (registerName == "dir") {
|
||||||
padDescriptor.gpioPortClearAddress = (portPeripheralRegisterGroup.has_value()
|
padDescriptor.gpioDdrAddress = (
|
||||||
&& portPeripheralRegisterGroup->offset.has_value()) ?
|
portPeripheralRegisterGroup.has_value()
|
||||||
portPeripheralRegisterGroup->offset.value_or(0) : 0;
|
&& portPeripheralRegisterGroup->offset.has_value()
|
||||||
|
)
|
||||||
padDescriptor.gpioPortClearAddress = padDescriptor.gpioPortClearAddress.value()
|
? portPeripheralRegisterGroup->offset.value_or(0) + portRegister.offset
|
||||||
+ portRegister.offset;
|
: 0 + portRegister.offset;
|
||||||
|
|
||||||
} else if (registerName.find("dirset") == 0) {
|
|
||||||
padDescriptor.ddrSetAddress = (portPeripheralRegisterGroup.has_value()
|
|
||||||
&& portPeripheralRegisterGroup->offset.has_value()) ?
|
|
||||||
portPeripheralRegisterGroup->offset.value_or(0) : 0;
|
|
||||||
|
|
||||||
padDescriptor.ddrSetAddress = padDescriptor.ddrSetAddress.value()
|
|
||||||
+ portRegister.offset;
|
|
||||||
|
|
||||||
} else if (registerName.find("dirclr") == 0) {
|
|
||||||
padDescriptor.ddrClearAddress = (portPeripheralRegisterGroup.has_value()
|
|
||||||
&& portPeripheralRegisterGroup->offset.has_value()) ?
|
|
||||||
portPeripheralRegisterGroup->offset.value_or(0) : 0;
|
|
||||||
|
|
||||||
padDescriptor.ddrClearAddress = padDescriptor.ddrClearAddress.value()
|
|
||||||
+ portRegister.offset;
|
|
||||||
|
|
||||||
} else if (registerName == "in") {
|
} else if (registerName == "in") {
|
||||||
padDescriptor.gpioPortInputAddress = (portPeripheralRegisterGroup.has_value()
|
padDescriptor.gpioPortInputAddress = (
|
||||||
&& portPeripheralRegisterGroup->offset.has_value()) ?
|
portPeripheralRegisterGroup.has_value()
|
||||||
portPeripheralRegisterGroup->offset.value_or(0) : 0;
|
&& portPeripheralRegisterGroup->offset.has_value()
|
||||||
|
)
|
||||||
padDescriptor.gpioPortInputAddress = padDescriptor.gpioPortInputAddress.value()
|
? portPeripheralRegisterGroup->offset.value_or(0) + portRegister.offset
|
||||||
+ portRegister.offset;
|
: 0 + portRegister.offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -570,7 +553,7 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription
|
|||||||
|
|
||||||
if (this->padDescriptorsByName.contains(targetPin.padName)) {
|
if (this->padDescriptorsByName.contains(targetPin.padName)) {
|
||||||
const auto& pad = this->padDescriptorsByName.at(targetPin.padName);
|
const auto& pad = this->padDescriptorsByName.at(targetPin.padName);
|
||||||
if (pad.gpioPortSetAddress.has_value() && pad.ddrSetAddress.has_value()) {
|
if (pad.gpioPortAddress.has_value() && pad.gpioDdrAddress.has_value()) {
|
||||||
targetPin.type = TargetPinType::GPIO;
|
targetPin.type = TargetPinType::GPIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user