Rotate a 7-segment display in firmware

I have a board with a 7-segment display controlled by an AVR. I need to rotate the display's characters in the firmware, so that the display is read correctly when physically rotated 180 degrees.

Currently, the display has an output defined by:

#define SEVEN_SEGMENT_PATTERN_0     0x7B
#define SEVEN_SEGMENT_PATTERN_1     0x09
#define SEVEN_SEGMENT_PATTERN_2     0xB3
#define SEVEN_SEGMENT_PATTERN_3     0x9B
#define SEVEN_SEGMENT_PATTERN_4     0xC9
#define SEVEN_SEGMENT_PATTERN_5     0xDA
#define SEVEN_SEGMENT_PATTERN_6     0xFa
#define SEVEN_SEGMENT_PATTERN_7     0x0B
#define SEVEN_SEGMENT_PATTERN_8     0xFB
#define SEVEN_SEGMENT_PATTERN_9     0xDB

#define SEVEN_SEGMENT_PATTERN_A     0xEB
#define SEVEN_SEGMENT_PATTERN_B     0xF8
#define SEVEN_SEGMENT_PATTERN_C     0x72
#define SEVEN_SEGMENT_PATTERN_D     0xB9
#define SEVEN_SEGMENT_PATTERN_E     0xF2
#define SEVEN_SEGMENT_PATTERN_F     0xE2

#define SEVEN_SEGMENT_PATTERN_G     0xdb
#define SEVEN_SEGMENT_PATTERN_H     0xE9
#define SEVEN_SEGMENT_PATTERN_I     0x09
#define SEVEN_SEGMENT_PATTERN_J     0x19
#define SEVEN_SEGMENT_PATTERN_L     0x70
#define SEVEN_SEGMENT_PATTERN_O     0x7b
#define SEVEN_SEGMENT_PATTERN_P     0xe3
#define SEVEN_SEGMENT_PATTERN_R     0xa0
#define SEVEN_SEGMENT_PATTERN_S     0xda
#define SEVEN_SEGMENT_PATTERN_U     0x79

#define SEVEN_SEGMENT_PATTERN_DOT   0x04


Of course, I could use this to extract the pinout of the display and manually figure out the new definitions for flipped characters. However, this would be time consuming and I'm thinking that there must be a smarter way.

Some would remain the same when flipped, such as SEVEN_SEGMENT_PATTERN_0. Some will be easy to flip if I knew the pinout, such as SEVEN_SEGMENT_PATTERN_1.

Is there some smart algorithm or whatever that can help me calculate the flipped values?

Looks like the pinout is, from most to least significant bit, G F E D C dot A B.

You could write some code along the lines of

rotatedChar=0;
if (char & 0x01) rotatedChar|=0x20;
if (char & 0x02) rotatedChar|=0x10;
// six more lines here.

• While rotatedChar += 0x20; is correct, I think it would be more obvious to someone reading the code, for it to or the bits in, e.g. rotatedChar |= 0x20; instead. Using += looks like counting or a calculation, while |= looks like building a bit pattern. – gbulmer Sep 19 '14 at 8:41
• @gbulmer Good idea - code changed – Chris Johnson Sep 19 '14 at 9:50

Initial order of segments is GFEDCPAB and it has to be changed to GCBAFPDE. G and P stay at their places. B,D,F are rotated three positions right. A,C,E are rotated three positions left. AVRs can not do circular shift easily, so data is nibble-swapped twice to avoid shifting between LSB and MSB.

unsigned char dataout;
asm volatile("swap %0" : "=r" (datain) : "0" (datain));
dataout = ((datain & 0x15)<<2)|(datain & 0xa2))>>1;
asm volatile("swap %0" : "=r" (datain) : "0" (datain));
dataout |= datain & 0x84;


The answer above solved this. The remap function looks like this in Python (for testing):

def rotate(char):
rotatedchar = 0
if (char & 0x01):
rotatedchar += 0x20
if (char & 0x02):
rotatedchar += 0x10
if (char & 0x04):
rotatedchar += 0x04
if (char & 0x08):
rotatedchar += 0x40
if (char & 0x10):
rotatedchar += 0x02
if (char & 0x20):
rotatedchar += 0x01
if (char & 0x40):
rotatedchar += 0x04
if (char & 0x80):
rotatedchar += 0x80
return rotatedchar


It may be unnecessary optimalization, but in general, & is faster than if, therefore, using the coding from Chris' answer, we can get:

rotch = ch&0x84 + (ch & 0x0a) << 3 + (ch & 0x50) >> 3 + (ch & 0x01) << 5 + (ch & 0x20) >> 5


This comes from the fact that:

• for 0x08 and 0x02 in ch (G, dot), we keep them
• for 0x40 and 0x10 in ch (F, D), we shift them 3 bits to the right in rotch (to C, A)
• etc.

This is faster and it's a one-liner. From the code itself, it's obvious that it's just some but shuffle, yet it may be wise to comment it well.

• The compiler will generate equivalent code in either case. Which is clearer to read probably depends on the reader. – pericynthion Sep 19 '14 at 16:35
• I was anticipating that the code would be used just to get new values to hardcode into the #defines - which would be even more optimised! – Chris Johnson Sep 19 '14 at 21:23