Recent

Author Topic: Does anybody have example code for UART for the ATMEGA16A ?  (Read 506 times)

pascalbythree

  • Full Member
  • ***
  • Posts: 121
Does anybody have example code for UART for the ATMEGA16A ?
« on: September 26, 2022, 06:11:44 pm »
I only get it to work for the ATMEGA328P

Does anybody have a example code for the serial port for ATMEGA16A ?

That will be  a great thanks, Groet, Wouter

d.ioannidis

  • Full Member
  • ***
  • Posts: 200
    • Nephelae
Re: Does anybody have example code for UART for the ATMEGA16A ?
« Reply #1 on: September 26, 2022, 07:54:18 pm »
Hi,

you could try this :

Code: Pascal  [Select][+][-]
  1. unit ufp_uartserial;
  2.  
  3. {
  4.  
  5.   UART AVR.
  6.  
  7.   Copyright (C) 2022 Dimitrios Chr. Ioannidis.
  8.     Nephelae - https://www.nephelae.eu
  9.  
  10.   https://www.nephelae.eu/
  11.  
  12.   Licensed under the MIT License (MIT).
  13.   See licence file in root directory.
  14.  
  15.   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  16.   ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  17.   TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  18.   PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
  19.   SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  20.   ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  21.   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22.   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23.   OTHER DEALINGS IN THE SOFTWARE.
  24.  
  25. }
  26.  
  27. {$mode objfpc}
  28. {$modeswitch result-}
  29. {$modeswitch advancedrecords}
  30. {$longstrings off}
  31. {$writeableconst off}
  32. {$inline on}
  33. {$macro on}
  34.  
  35. {$if defined(fpc_mcu_atmega328p) }
  36.   {$DEFINE UART_UCSRA := UCSR0A }
  37.   {$DEFINE UART_UCSRB := UCSR0B }
  38.   {$DEFINE UART_UCSRC := UCSR0C }
  39.   {$DEFINE UART_UBRRL := UBRR0L }
  40.   {$DEFINE UART_UBRRH := UBRR0H }
  41.   {$DEFINE UART_UDR   := UDR0   }
  42.   {$DEFINE UART_UDRE  := UDRE0  }
  43.   {$DEFINE UART_TXEN  := TXEN0  }
  44.   {$DEFINE UART_RXEN  := RXEN0  }
  45.   {$DEFINE UART_RXC   := RXC0   }
  46.   {$DEFINE UART_U2X   := U2X0   }
  47. {$elseif defined(fpc_mcu_atmega16a) or defined(fpc_mcu_attiny2313)}
  48.   {$DEFINE UART_UCSRA := UCSRA }
  49.   {$DEFINE UART_UCSRB := UCSRB }
  50.   {$DEFINE UART_UCSRC := UCSRC }
  51.   {$DEFINE UART_UBRRL := UBRRL }
  52.   {$DEFINE UART_UBRRH := UBRRH }
  53.   {$DEFINE UART_UDR   := UDR   }
  54.   {$DEFINE UART_UDRE  := UDRE  }
  55.   {$DEFINE UART_TXEN  := TXEN  }
  56.   {$DEFINE UART_RXEN  := RXEN  }
  57.   {$DEFINE UART_RXC   := RXC   }
  58.   {$DEFINE UART_U2X   := U2X   }
  59. {$endif}
  60.  
  61.  
  62. interface
  63.  
  64. type
  65.  
  66.   { TUART }
  67.  
  68.   TUART = packed record
  69.   public
  70.     procedure Init(const ABaudRate: UInt32 = 57600);
  71.     function ReadChar: Char;
  72.     procedure WriteChar(const AChar: char);
  73.     procedure WriteStr(const s: ShortString = '');
  74.     procedure WriteStrLn(const s: ShortString = '');
  75.   end;
  76.  
  77. var
  78.   UART: TUART;
  79.  
  80. implementation
  81.  
  82. { TUART }
  83.  
  84. procedure TUART.Init(const ABaudRate: UInt32);
  85. var
  86.   Prescaler: UInt16;
  87. begin
  88.   //Prescaler := ((F_CPU div 4) div ABaudRate - 1) div 2;
  89.   Prescaler := F_CPU div 8 div ABaudRate - 1;
  90.  
  91.   UART_UBRRL  :=  Prescaler;
  92.   UART_UCSRA := (1 shl UART_U2X);
  93.   UART_UCSRB := (1 shl UART_TXEN) or (1 shl UART_RXEN);
  94.   UART_UCSRC := %10000110;
  95. end;
  96.  
  97. procedure TUART.WriteChar(const AChar: char); inline;
  98. begin
  99.   while ((UART_UCSRA and (1 shl UART_UDRE)) = 0) do ;
  100.   UART_UDR := byte(AChar);
  101. end;
  102.  
  103. function TUART.ReadChar: Char;
  104. begin
  105.   while ((UART_UCSRA and (1 shl UART_RXC)) = 0) do ;
  106.   ReadChar := Char(UART_UDR);
  107. end;
  108.  
  109. procedure TUART.WriteStr(const s: ShortString);
  110. var
  111.   i: integer;
  112. begin
  113.   if length(s) > 0 then
  114.   begin
  115.     for i := 1 to length(s) do
  116.        WriteChar(s[i]);
  117.   end;
  118. end;
  119.  
  120. procedure TUART.WriteStrLn(const s: ShortString);
  121. begin
  122.   WriteStr(s);
  123.   WriteStr(#13#10);
  124. end;
  125.  
  126. end.

I quickly added the ifdef's didn't test it with a physical mcu .

Forgot to add that its hardcoded 8bit, no parity and 1 stop bit . Also there is a global variable UART so you just add the unit to the uses clause.

Code: Pascal  [Select][+][-]
  1. program fp_uart_test;
  2.  
  3. {$mode objfpc}
  4. {$writeableconst off}
  5. {$longstrings off}
  6.  
  7. uses
  8.   ufp_uartserial;
  9.  
  10. const
  11.   BannerTopStr: string[27] = #13#10'-------------------------';
  12.   BannerStr: string[17] = 'Free Pascal Rocks';
  13.  
  14. begin
  15.   UART.Init(9600);
  16.  
  17.   UART.WriteStrLn(BannerTopStr);
  18.   UART.WriteStrLn(BannerStr);
  19.  
  20. end.

If it doesn't work I have a DIP atmega16a I could try in a breadboard .... ;)

EDIT: Added sample project ....

EDIT2: Added attiny2313 ;)

regards,
« Last Edit: September 28, 2022, 10:17:32 pm by d.ioannidis »

d.ioannidis

  • Full Member
  • ***
  • Posts: 200
    • Nephelae
Re: Does anybody have example code for UART for the ATMEGA16A ?
« Reply #2 on: September 26, 2022, 11:47:05 pm »
Hi,

  also forgot to mention, the fpc_mcu_* define ( fpc_mcu_atmega328p, fpc_mcu_attiny861 etc ) is generated by the compiler with the Wp target-specific option, so don't try to define it your self.

regards,
« Last Edit: September 26, 2022, 11:48:44 pm by d.ioannidis »

pascalbythree

  • Full Member
  • ***
  • Posts: 121
Re: Does anybody have example code for UART for the ATMEGA16A ?
« Reply #3 on: September 27, 2022, 03:09:44 pm »
Does not seem to work on my NT4 machine and PUTTY on it. Anybody got more example code for the UART on the ATMEGA16A?

PS: I just bought 5 pcs of Attiny2313 on a dutch webshop

When they arrive i maybe also need some extra help getting this attiny and his UART to run.

Example program from fpc-avr

Code: Pascal  [Select][+][-]
  1. program uart1;
  2.  
  3. uses uart, delay{, integermath};
  4.  
  5. const
  6.   baud = 115200;
  7.   // UseU2X = true
  8.   ub = (((F_CPU + 4*BAUD) shr 3) div BAUD) - 1;
  9.   PB5 = 1 shl 5;
  10.  
  11. var
  12.   c: byte;
  13.   pinport: byte absolute PORTB;
  14.   pindir: byte absolute DDRB;
  15.  
  16. begin
  17.   uart_init1(BAUD, false);
  18.   //uart_init(ub);
  19.   pindir := PB5;
  20.  
  21.   repeat
  22.     c := uart_receive();    // blocking
  23.     pinport := pinport XOR PB5; // toggle LED
  24.     uart_transmit(ord('#'));
  25.  
  26.     uart_transmit(c);
  27.     uart_transmit(13);
  28.   until false;
  29. end.
  30.  

default unit from FPC-AVR
Code: Pascal  [Select][+][-]
  1. unit uart;
  2.  
  3. interface
  4. // Automatically use U2X
  5. procedure uart_init(const UBRR: word);
  6.  
  7. procedure uart_init1(const BAUD: dword; const useU2X: boolean = false);
  8.  
  9. // Blocking functions
  10. procedure uart_transmit(const data: byte); overload;
  11. procedure uart_transmit_hex(const data: byte); overload;
  12. procedure uart_transmit_hex(const data: word); overload;
  13. procedure uart_transmit_hex(const data: dword); overload;
  14. procedure uart_transmit(const s: shortstring); overload;
  15.  
  16. procedure uart_transmit_asstring(b: byte); overload;
  17. procedure uart_transmit_asstring(b: int8); overload;
  18. procedure uart_transmit_asstring(b: word); overload;
  19. procedure uart_transmit_asstring(b: int16); overload;
  20. procedure uart_transmit_asstring(b: dword); overload;
  21. procedure uart_transmit_asstring(b: int32); overload;
  22.  
  23. function uart_receive: byte;
  24. function uart_peek(out c: byte): boolean;
  25.  
  26. implementation
  27.  
  28. uses
  29.   simplemath;
  30.  
  31. {$ifdef CPUAVRXMEGA3}
  32. procedure uart_init(const UBRR: word);
  33. begin
  34.   // RX
  35.   PORTB.DIRCLR := PIN1bm;
  36.   // TX
  37.   PORTB.OUTSET := Pin0bm;
  38.   PORTB.DIRSET := Pin0bm;
  39.  
  40.   USART3.BAUD := UBRR;
  41.   //USART3.CTRLA := TUSART.RXCIEbm;  // RX is interrupt driven
  42.   USART3.CTRLB := TUSART.RXENbm or TUSART.TXENbm;
  43. end;
  44.  
  45. procedure uart_init1(const BAUD: dword; const useU2X: boolean = false);
  46. var
  47.   ubrr: word;
  48. begin
  49.   // RX
  50.   PORTB.DIRCLR := PIN1bm;
  51.   // TX
  52.   PORTB.OUTSET := Pin0bm;
  53.   PORTB.DIRSET := Pin0bm;
  54.  
  55.   if useU2X then
  56.     ubrr := (F_CPU * 64 + 4 * BAUD) div (8 * BAUD)
  57.   else
  58.     //ubrr := (F_CPU * 64 + 8 * BAUD) div (16 * BAUD);
  59.     ubrr := (F_CPU * 8 + BAUD) div (2 * BAUD);
  60.  
  61.   USART3.BAUD := ubrr;
  62.   USART3.CTRLB := TUSART.RXENbm or TUSART.TXENbm;
  63. end;
  64.  
  65. // Blocking functions
  66. procedure uart_transmit(const data: byte);
  67. begin
  68.   repeat
  69.   until (USART3.STATUS and TUSART.DREIFbm = TUSART.DREIFbm);
  70.   USART3.TXDATAL := data;
  71. end;
  72.  
  73. function uart_receive(): byte;
  74. begin
  75.   repeat
  76.   until (USART3.STATUS and TUSART.RXCIFbm = TUSART.RXCIFbm);
  77.   result := USART3.RXDATAL;
  78. end;
  79.  
  80. function uart_peek(c: byte): byte;
  81. begin
  82.   result := (USART3.STATUS and TUSART.RXCIFbm) = TUSART.RXCIFbm;
  83.   c := USART3.RXDATAL;
  84. end;
  85.  
  86. {$else}
  87. procedure uart_init1(const BAUD: dword; const useU2X: boolean = false);
  88. var
  89.   ubrr: word;
  90. begin
  91.   if useU2X then
  92.     ubrr := ((F_CPU + 4*BAUD) shr 3) div BAUD
  93.   else
  94.     ubrr := ((F_CPU + 8*BAUD) shr 4) div BAUD;
  95.  
  96.   UBRR0 := ubrr-1;
  97.  
  98.   // Set U2X as specified
  99.   UCSR0A := UCSR0A or (byte(useU2X) shl U2X0);
  100.  
  101.   // Enable receiver and transmitter
  102.   UCSR0B := (1 shl RXEN0) or (1 shl TXEN0);
  103.  
  104.   // Set frame format: 8data, 1stop bit, no parity
  105.   UCSR0C := (3 shl UCSZ0);
  106. end;
  107.  
  108. procedure uart_init(const UBRR: word);
  109. begin
  110.   UBRR0H := UBRR shr 8;
  111.   UBRR0L := byte(UBRR);
  112.  
  113.   // Set U2X bit
  114.   UCSR0A := UCSR0A or (1 shl U2X0);
  115.  
  116.   // Enable receiver and transmitter
  117.   UCSR0B := (1 shl RXEN0) or (1 shl TXEN0);
  118.  
  119.   // Set frame format: 8data, 1stop bit, no parity
  120.   UCSR0C := (3 shl UCSZ0);
  121. end;
  122.  
  123. procedure uart_transmit(const data: byte);
  124. begin
  125.   // Wait for empty transmit buffer
  126.   while ((UCSR0A and (1 shl UDRE0)) = 0) do;
  127.  
  128.   // Put data into buffer, sends the data
  129.   UDR0 := data;
  130. end;
  131.  
  132. function uart_receive: byte;
  133. begin
  134.   // Wait for data to be received
  135.   while ((UCSR0A and (1 shl RXC0)) = 0) do;
  136.  
  137.   // Get and return received data from buffer
  138.   result := UDR0;
  139. end;
  140.  
  141. function uart_peek(out c: byte): boolean;
  142. begin
  143.   result := UCSR0A and (1 shl RXC0) > 0;
  144.   c := UDR0;
  145. end;
  146.  
  147. {$endif CPUAVRXMEGA3}
  148.  
  149. procedure uart_transmit_hex(const data: byte);
  150. var
  151.   n, d: byte; // nibbles 1&2
  152. begin
  153.   n := data shr 4;
  154.   if n < 10 then
  155.     d := $30 + n
  156.   else
  157.     d := ord('A') + (n - 10);
  158.   uart_transmit(d);
  159.  
  160.   n := data and $0F;
  161.   if n < 10 then
  162.     d := $30 + n
  163.   else
  164.     d := ord('A') + (n - 10);
  165.   uart_transmit(d);
  166. end;
  167.  
  168. procedure uart_transmit_hex(const data: word);
  169. begin
  170.   uart_transmit_hex(hi(data));
  171.   uart_transmit_hex(lo(data));
  172. end;
  173.  
  174. procedure uart_transmit_hex(const data: dword);
  175. begin
  176.   uart_transmit_hex(hi(data));
  177.   uart_transmit_hex(lo(data));
  178. end;
  179.  
  180. procedure uart_transmit(const s: shortstring);
  181. var
  182.   i: byte;
  183. begin
  184.   for i := 1 to length(s) do
  185.     uart_transmit(ord(s[i]));
  186. end;
  187.  
  188. procedure uart_transmit_asstring(b: byte);
  189. var
  190.   d, temp: byte;
  191.   skipLeadingZero: boolean;
  192. begin
  193.   if b = 0 then
  194.     uart_transmit(ord('0'))
  195.   else
  196.   begin
  197.     skipLeadingZero := true;
  198.     d := 2;  // 100 = 10^2
  199.     repeat
  200.       temp := b;
  201.       decimalDivMod(temp, b, d);
  202.       if not skipLeadingZero or (temp > 0) then
  203.       begin
  204.         skipLeadingZero := false;
  205.         uart_transmit(temp + ord('0'));
  206.       end;
  207.       dec(d);
  208.       if d = 0 then
  209.         uart_transmit(b + ord('0'));
  210.     until d = 0;
  211.   end;
  212. end;
  213.  
  214. procedure uart_transmit_asstring(b: int8);
  215. begin
  216.   if b < 0 then
  217.   begin
  218.     b := -b;
  219.     uart_transmit(ord('-'));
  220.   end;
  221.   uart_transmit_asstring(byte(b));
  222. end;
  223.  
  224. procedure uart_transmit_asstring(b: word);
  225. var
  226.   d, temp: word;
  227.   skipLeadingZero: boolean;
  228. begin
  229.   if b = 0 then
  230.     uart_transmit(ord('0'))
  231.   else
  232.   begin
  233.     skipLeadingZero := true;
  234.     d := 4;  // 10000 = 10^4
  235.     repeat
  236.       temp := b;
  237.       decimalDivMod(temp, b, d);
  238.       if not skipLeadingZero or (temp > 0) then
  239.       begin
  240.         skipLeadingZero := false;
  241.         uart_transmit(temp + ord('0'));
  242.       end;
  243.       dec(d);
  244.       if d = 0 then
  245.         uart_transmit(b + ord('0'));
  246.     until d = 0;
  247.   end;
  248. end;
  249.  
  250. procedure uart_transmit_asstring(b: int16);
  251. begin
  252.   if b < 0 then
  253.   begin
  254.     b := -b;
  255.     uart_transmit(ord('-'));
  256.   end;
  257.   uart_transmit_asstring(word(b));
  258. end;
  259.  
  260. procedure uart_transmit_asstring(b: dword);
  261. var
  262.   d, temp: dword;
  263.   skipLeadingZero: boolean;
  264. begin
  265.   if b = 0 then
  266.     uart_transmit(ord('0'))
  267.   else
  268.   begin
  269.     skipLeadingZero := true;
  270.     d := 10;
  271.     repeat
  272.       temp := b;
  273.       decimalDivMod(temp, b, d);
  274.       if not skipLeadingZero or (temp > 0) then
  275.       begin
  276.         skipLeadingZero := false;
  277.         uart_transmit(byte(temp) + ord('0'));
  278.       end;
  279.       dec(d);
  280.       if d = 0 then
  281.         uart_transmit(byte(b) + ord('0'));
  282.     until d = 0;
  283.   end;
  284. end;
  285.  
  286. procedure uart_transmit_asstring(b: int32);
  287. begin
  288.   if b < 0 then
  289.   begin
  290.     b := -b;
  291.     uart_transmit(ord('-'));
  292.   end;
  293.   uart_transmit_asstring(dword(b));
  294. end;
  295.  
  296. end.
  297.  

Anybody know what to change to get it to run on the ATMEGA16A instead of atmega328p ?

That you for your time in advance and greets, Wouter !

d.ioannidis

  • Full Member
  • ***
  • Posts: 200
    • Nephelae
Re: Does anybody have example code for UART for the ATMEGA16A ?
« Reply #4 on: September 27, 2022, 04:41:01 pm »
Hi,

Does not seem to work on my NT4 machine and PUTTY on it. Anybody got more example code for the UART on the ATMEGA16A?
<snip>

Just tested it on a breadboard with a breakout atmega16 board and it works .
( The atmega16 I have wasn't DIP but that's ok ).

Are macros enabled ( -Sm ) ?
Is the F_CPU define present and correct ? ( If your mcu runs at 8MHz you need to use -dF_CPU:=8000000 )

Here is a copy of my Lazarus custom options :

Code: Pascal  [Select][+][-]
  1. -a
  2. -al
  3. -Xe
  4. -Xm
  5. -Sm
  6. -WpATMEGA16A
  7. -CpAVR5
  8. -dF_CPU:=1000000

Notice that the mcu I tested runs at 1MHz with the internal osc.

regards,
« Last Edit: September 27, 2022, 04:49:08 pm by d.ioannidis »

d.ioannidis

  • Full Member
  • ***
  • Posts: 200
    • Nephelae
Re: Does anybody have example code for UART for the ATMEGA16A ?
« Reply #5 on: September 27, 2022, 05:24:20 pm »

< snip >

Anybody know what to change to get it to run on the ATMEGA16A instead of atmega328p ?

If you look in my first post, the main difference between atmega328p and atmega16a, is that the UART registers in atmega328p have a zero 0 in their name .

Code: Pascal  [Select][+][-]
  1. {$if defined(fpc_mcu_atmega328p) }
  2.   {$DEFINE UART_UCSRA := UCSR0A }
  3. ......
  4. {$elseif defined (fpc_mcu_atmega16a) }
  5.   {$DEFINE UART_UCSRA := UCSRA }
  6. ......
  7.  

Look at the ifdef in my code and substitute the atmega328p register names with the atmega16a register names in the code you posted. It should work.

regards,

d.ioannidis

  • Full Member
  • ***
  • Posts: 200
    • Nephelae
Re: Does anybody have example code for UART for the ATMEGA16A ?
« Reply #6 on: September 28, 2022, 10:28:21 pm »
Hi,

PS: I just bought 5 pcs of Attiny2313 on a dutch webshop

When they arrive i maybe also need some extra help getting this attiny and his UART to run.
< snip >

in my first post, I edit the code to support also attiny2313 ( added a define and switched the Prescaler calculation to use less memory ;)  ) .

Tested with a physical mcu  ....

regards,
« Last Edit: September 28, 2022, 10:55:05 pm by d.ioannidis »

 

TinyPortal © 2005-2018