Without if's or divs. Channels 5 - 7 are used for padding the unused entries. Note for the Arduino: The const tables are not in ROM address spscae:
#include <stdint.h>
typedef struct
{
uint16_t data; // output data
uint8_t next; // next channel index
}
ChannelEntry_t;
const ChannelEntry_t channel[] = {
{0x400, 1}, /* 0 */
{0x403, 2}, /* 1 */
{0x408, 3}, /* 2 */
{0x409, 4}, /* 3 */
{0x40C, 0}, /* 4 */
{0x400, 0}, /* 5, unused */
{0x400, 0}, /* 6, unused */
{0x400, 0} /* 7, unused */
};
extern void do_something(uint16_t dataval);
uint8_t chnum = 0;
int main ()
{
while (1)
{
uint16_t dataval = channel[chnum & 0x07].data;
chnum = channel[chnum & 0x07].next;
do_something(dataval);
}
return 0;
}
Arduino AVR C++ compiler output disassembly:
Disassembly of section .text.startup.main:
00000000 <main>:
0: 80 91 00 00 lds r24, 0x0000
4: 87 70 andi r24, 0x07 ; 7
6: 90 e0 ldi r25, 0x00 ; 0
8: fc 01 movw r30, r24
a: ee 0f add r30, r30
c: ff 1f adc r31, r31
e: e8 0f add r30, r24
10: f9 1f adc r31, r25
12: e0 50 subi r30, 0x00 ; 0
14: f0 40 sbci r31, 0x00 ; 0
16: 80 81 ld r24, Z
18: 91 81 ldd r25, Z+1 ; 0x01
1a: 22 81 ldd r18, Z+2 ; 0x02
1c: 20 93 00 00 sts 0x0000, r18
20: 0e 94 00 00 call 0 ; 0x0 <main>
24: 00 c0 rjmp .+0 ; 0x26 <__zero_reg__+0x25>
Same thing using pointers:
#include <stdint.h>
struct ChannelEntry_t;
typedef struct ChannelEntry_t
{
uint16_t data; // output data
const ChannelEntry_t * next; // next channel entry
}
ChannelEntry_t;
const ChannelEntry_t channel[] = {
{0x400, &channel[1]}, /* 0 */
{0x403, &channel[2]}, /* 1 */
{0x408, &channel[3]}, /* 2 */
{0x409, &channel[4]}, /* 3 */
{0x40C, &channel[0]} /* 4 */
};
extern void do_something(uint16_t dataval);
const ChannelEntry_t * chdata = &channel[0];
int main ()
{
while (1)
{
uint16_t dataval = chdata->data;
chdata = chdata->next;
do_something(dataval);
}
return 0;
}
and the disaasembly:
Disassembly of section .text.startup.main:
00000000 <main>:
0: e0 91 00 00 lds r30, 0x0000
4: f0 91 00 00 lds r31, 0x0000
8: 80 81 ld r24, Z
a: 91 81 ldd r25, Z+1 ; 0x01
c: 22 81 ldd r18, Z+2 ; 0x02
e: 33 81 ldd r19, Z+3 ; 0x03
10: 30 93 00 00 sts 0x0000, r19
14: 20 93 00 00 sts 0x0000, r18
18: 0e 94 00 00 call 0 ; 0x0 <main>
1c: 00 c0 rjmp .+0 ; 0x1e <__zero_reg__+0x1d>
The pointer implementation is pretty efficient and straight forward, and it doesn't require if's nor modulus.