0

I'm currently working on some peripheral drivers for a family of microprocessors. I need to write code for devices that are very similar that in some cases only vary in the number of peripherals.

I would like to write a driver for the UART peripheral but in some devices of the family there's only one available and for others there are two. The driver for UART2 y the same as for UART1 but instead of writing to UART1FOO register I need to write to UART2FOO register. Knowing this I would like to write a piece of code where a macro is able to repeat a big chunk of code but replacing the number of the register reference.

The ideal solution would be something like:

// File: uartdriver.h

#if __device1__
#define PRESENT_UARTS 1
#else
#define PRESENT_UARTS 2
#endif

#for CURRENT_ITEM in MAGIC_MACRO_THAT_RETURNS_LIST(PRESENT_UARTS)

  void uart#CURRENT_ITEM#_init();

#endfor

I know that this pseudo code does not exist but I have also seen people do magic with macros. I must use C code and not C++ and I'm aware that the use of macros may not be the most friendly way to write this but I don't like to repeat code with such small variations.

What would be the best solutions that mimic the pseudocode above? Any other hint or advice? Is there any other alternative to macros in this situation?

Thank you very much for your time.

  • 2
    Why duplicate the actual code? Can you not just use config data structs, one of each peripheral instance? – Martin James Apr 23 '16 at 15:44
  • Sorry but I can't really understand what you mean. I would like to independently configure each of the peripherals. That means writting more than 20 values/flags to those registers. For example `void uart1_init(uint16_t baudrate) { UART1.ON=0; UART1.BAUDRATE=baudrate/CLOCK_CONSTANT;}` so I don't want to rewrite the same function for UART2 and I also want the user to avoid the pain of reading the documentation about the config data structs. – Antonio Vázquez Blanco Apr 23 '16 at 15:49
  • You can have a helper function to set them up. – Martin James Apr 23 '16 at 16:05
  • Please, can you ellaborate? I am not sure I'm following you. Thank you very much. – Antonio Vázquez Blanco Apr 23 '16 at 16:07
  • They mean why don't you create a function for initialization that can take the port address as a parameter. Anyway take a look here for some suggestions: http://stackoverflow.com/questions/319328/writing-a-while-loop-in-the-c-preprocessor – Frankie_C Apr 23 '16 at 16:15
  • As @MartinJames, and the structs can also hold buffer information - if your code is sophisticated enough to be driven by interrupts (as it should be). Best to use "macro magic" only as a last resort. – Weather Vane Apr 23 '16 at 16:26
  • @Frankie_C That should reduce the size of code while simplifying the use of macros in order to call the helper functions in case I want full abstraction of the hardware for the user. – Antonio Vázquez Blanco Apr 23 '16 at 16:28

1 Answers1

1

I think some people are suggesting something along the lines of this. Note, this is pseudo code ie I just typed this in without testing it so it likely has some bugs etc.

typedef uint8_t uart_id; 
int uart_init(uart_id id, uint16_t baudrate);

typedef struct uart_definitions  {
  uart_id  id;
  uint16_t baudrate;
  ....
} udefs;

#define MAX_UDEFS 2
static udefs u_config[MAX_UDEFS] = {
    {0, 1000},
    {1, 8192}
};

uart_init(uart_id id, uint16_t brate) {
   assert(id <= MAX_UDEFS);
   u_config[id].baudrate = brate;
   .....
}
Harry
  • 11,298
  • 1
  • 29
  • 43