You can do this with an Uno, provided it has nothing else to do. I would
program it low-level, skipping the Arduino core since, as you said,
digitalWrite()
would be too slow for this application.
Here is my proposed approach: read the 4-bit input from one port, use a look-up table to translate it to an 8-bit output, and write that output to another port. I would use PORTD (pins 0–7) for the output, as it is the only full 8-bit port on the Uno, then the first bits of PORTB (pins 8–11) for the input:
/* Translation look-up table (dummy example). */
const uint8_t lut[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
};
int main() {
DDRB = 0x00; // set port B as input
DDRD = 0xff; // set port D as output
for (;;) {
uint8_t input = PINB & 0x0f; // grab the lowest 4 bits
PORTD = lut[input]; // set the output
}
}
I compiled and disassembled this code to count the CPU cycles: the main loop takes 10 cycles per iteration. Given that the Uno is clocked at 16 MHz, this is one update of the output every 0.625 μs.
Edit: This is a straightforward approach. At the cost of some extra complexity, it could be optimized down to 7 cycles per iteration (0.438 μs), or even 6 cycles (0.375 μs) in assembly.
You can do this with an Uno, provided it has nothing else to do. I would
program it low-level, skipping the Arduino core since, as you said,
digitalWrite()
would be too slow for this application.
Here is my proposed approach: read the 4-bit input from one port, use a look-up table to translate it to an 8-bit output, and write that output to another port. I would use PORTD (pins 0–7) for the output, as it is the only full 8-bit port on the Uno, then the first bits of PORTB (pins 8–11) for the input:
/* Translation look-up table (dummy example). */
const uint8_t lut[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
};
int main() {
DDRB = 0x00; // set port B as input
DDRD = 0xff; // set port D as output
for (;;) {
uint8_t input = PINB & 0x0f; // grab the lowest 4 bits
PORTD = lut[input]; // set the output
}
}
I compiled and disassembled this code to count the CPU cycles: the main loop takes 10 cycles per iteration. Given that the Uno is clocked at 16 MHz, this is one update of the output every 0.625 μs.
You can do this with an Uno, provided it has nothing else to do. I would
program it low-level, skipping the Arduino core since, as you said,
digitalWrite()
would be too slow for this application.
Here is my proposed approach: read the 4-bit input from one port, use a look-up table to translate it to an 8-bit output, and write that output to another port. I would use PORTD (pins 0–7) for the output, as it is the only full 8-bit port on the Uno, then the first bits of PORTB (pins 8–11) for the input:
/* Translation look-up table (dummy example). */
const uint8_t lut[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
};
int main() {
DDRB = 0x00; // set port B as input
DDRD = 0xff; // set port D as output
for (;;) {
uint8_t input = PINB & 0x0f; // grab the lowest 4 bits
PORTD = lut[input]; // set the output
}
}
I compiled and disassembled this code to count the CPU cycles: the main loop takes 10 cycles per iteration. Given that the Uno is clocked at 16 MHz, this is one update of the output every 0.625 μs.
Edit: This is a straightforward approach. At the cost of some extra complexity, it could be optimized down to 7 cycles per iteration (0.438 μs), or even 6 cycles (0.375 μs) in assembly.
You can do this with an Uno, provided it has nothing else to do. I would
program it low-level, skipping the Arduino core since, as you said,
digitalWrite()
would be too slow for this application.
Here is my proposed approach: read the 4-bit input from one port, use a look-up table to translate it to an 8-bit output, and write that output to another port. I would use PORTD (pins 0–7) for the output, as it is the only full 8-bit port on the Uno, then the first bits of PORTB (pins 8–11) for the input:
/* Translation look-up table (dummy example). */
const uint8_t lut[16] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
};
int main() {
DDRB = 0x00; // set port B as input
DDRD = 0xff; // set port D as output
for (;;) {
uint8_t input = PINB & 0x0f; // grab the lowest 4 bits
PORTD = lut[input]; // set the output
}
}
I compiled and disassembled this code to count the CPU cycles: the main loop takes 10 cycles per iteration. Given that the Uno is clocked at 16 MHz, this is one update of the output every 0.625 μs.