Recent

Author Topic: Large system, i2C to go with Freepascal on AVR, code help  (Read 2419 times)

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Large system, i2C to go with Freepascal on AVR, code help
« on: September 23, 2023, 11:42:26 am »
Hello people at freepascal.org

At the attached picture you can see my latest project. IMG_1428

It includes a raspberry 4 in a enclosure with 2 channels. For that it is equipped with two USB hubs for 6 different AVR USB programmers.

It switched with 2 board containing a 4066

So 2 channels, left en right to my TFT screen in de front panel.

It boots from a old 12V laptop adapter.

This system is controlled by a terminal app and a own delphi 10 application.

The SDA and SCL are connected with two 10K PULL-UP resistors

The code from our i2C unit:

Code: Pascal  [Select][+][-]
  1. unit i2c;
  2.  
  3. interface
  4.  
  5. type
  6.   { TI2CMaster }
  7.   TI2CMaster = object
  8.     retVal: byte;
  9.     procedure init(bitRate: byte);
  10.     // Low level functions
  11.     // Address should be left adjusted 7-bit value
  12.     function start(address: byte; readTransaction: boolean): boolean;
  13.     function readByte(out data: byte; ack: boolean): boolean;
  14.     function writeByte(data: byte): boolean;
  15.     function stop: boolean;
  16.  
  17.     // Higher level implementation
  18.     function ReadByteFromReg(i2caddress, regAddress: byte; out data: byte): boolean; overload;
  19.     function ReadBytesFromReg(i2caddress, regAddress: byte; data: PByte; size: byte): boolean; overload;
  20.     function ReadBytes(i2caddress: byte; const data: PByte; size: byte): boolean; overload;
  21.  
  22.     function WriteByteToReg(i2caddress, regAddress: byte; const data: byte): boolean; overload;
  23.     function WriteBytesToReg(i2caddress, regAddress: byte; data: PByte; size: byte
  24.       ): boolean; overload;
  25.     function WriteBytes(address: byte; const data: PByte; size: byte): boolean;
  26.  
  27.     // data pointer should be pointer to flash memory
  28.     function WriteBytesToReg_P(i2caddress, regAddress: byte; data: PByte; size: byte
  29.       ): boolean;
  30.  
  31.     function clearStalledBus: boolean;
  32.   end;


Code left channel:

Code: Pascal  [Select][+][-]
  1. program WVW_LEFT;
  2.  
  3. uses
  4.  i2c, delay;
  5.  
  6.   procedure ModePortB(Pin: byte; Value: Boolean);
  7.   begin
  8.     if Value then
  9.       begin
  10.         DDRB := DDRB or (1 shl pin);
  11.       end
  12.     else
  13.       begin
  14.         DDRB := DDRB and not (1 shl pin);
  15.       end;
  16.   end;
  17.  
  18. procedure WritePortB(Pin: byte; Value: Boolean);
  19.   begin
  20.     if Value then
  21.       begin
  22.         PORTB := PORTB or (1 shl pin);
  23.       end
  24.     else
  25.       begin
  26.         PORTB := PORTB and not (1 shl pin);
  27.     end;
  28.   end;
  29.  
  30. const  AddressI2C = $68;
  31.  
  32. var
  33.   i2c_master: TI2CMaster;
  34.   i, wb ,data: byte;
  35.   S:String;
  36.   C:Char;  
  37.  
  38. begin
  39.   i:=0;
  40.   wb:=0;
  41.   data:=0;
  42.   S:=' ';
  43.   C:=' ';  
  44.  
  45.   ModePortB(1, TRUE); // Status LED to output
  46.  
  47.   i2c_master.init(I2C_50kHz);
  48.  
  49.   S := 'Hello World!';
  50.  
  51.   repeat
  52.      inc(i);
  53.          if i = 12 then i:=1;
  54.  
  55.      i2c_master.start(AddressI2C,I2C_WriteMode);    
  56.          wb := Ord(S[i]);
  57.          i2c_master.writeByte(wb);
  58.      i2c_master.stop;    
  59.          
  60.          WritePortB(1,True);  // Status LED OFF
  61.          delay_ms(20);
  62.          WritePortB(1,False); // Status LED ON
  63.          delay_ms(20);   
  64.   until 1=2;     
  65. end.
  66.  


Code right channel:


Code: Pascal  [Select][+][-]
  1. program LCDtest;
  2.  
  3. uses lcd_config, lcd_hd44780, delay, i2c;
  4.  
  5.   procedure ModePortB(Pin: byte; Value: Boolean);
  6.   begin
  7.     if Value then
  8.       begin
  9.         DDRB := DDRB or (1 shl pin);
  10.       end
  11.     else
  12.       begin
  13.         DDRB := DDRB and not (1 shl pin);
  14.       end;
  15.   end;
  16.  
  17. procedure WritePortB(Pin: byte; Value: Boolean);
  18.   begin
  19.     if Value then
  20.       begin
  21.         PORTB := PORTB or (1 shl pin);
  22.       end
  23.     else
  24.       begin
  25.         PORTB := PORTB and not (1 shl pin);
  26.     end;
  27.   end;
  28.  
  29.     function IntToStr(const i: Integer): string;
  30.     begin
  31.      Str(i, Result);
  32.     end;
  33.      
  34.     function StrToInt(const s: string): Integer;
  35.     var
  36.      code: Integer;
  37.     begin
  38.      Val(s, Result, code);
  39.     end;  
  40.  
  41. const  AddressI2C = $68;
  42.  
  43. var
  44.   i2c_master: TI2CMaster;
  45.   i, Data: Byte;
  46.   C:Char;  
  47.   S:String;  
  48.  
  49. begin
  50.   i:=0;
  51.   C:=' ';
  52.   S:=' ';
  53.   Data := 0;
  54.  
  55.   ModePortB(1, TRUE); // Status LED to output
  56.  
  57.   lcd_init(lcd_displayOnCursorOnCursorBlink);
  58.   lcd_clrscr;
  59.  
  60.   i2c_master.init(I2C_50kHz);
  61.  
  62.    repeat
  63.     inc(i);
  64.     if i = 12 then begin i:=1; S:=''; lcd_clrscr; end;
  65.          
  66.     i2c_master.start(AddressI2C,I2C_ReadMode);
  67.     i2c_master.ReadByte(Data,False);
  68.         i2c_master.stop;
  69.         S := S + Chr(Data);
  70.        
  71.         lcd_gotoxy(1, 1); // Display
  72.     lcd_puts(S); // Send string to Display
  73.                  
  74.          WritePortB(1,True); // Status LED OFF
  75.          delay_ms(20);
  76.          WritePortB(1,False); // Status LED ON
  77.          delay_ms(20);
  78.   until 1=2;
  79. end.
  80.  


Now the question is weither somebode can help me out debugging this to pieces of pascal code. So it displays text on my lcd_hd44780 display. From the left MCU to the right MCU

Are you all crazy enough? Greets, PascalByThree, Wotuer van Wegen

PS: Al my MCU's on the breadboard are ATMEGA328P running at 8MHZ

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #1 on: September 23, 2023, 11:45:15 am »
Extra Photos:

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #2 on: September 23, 2023, 11:45:51 am »
-

ccrause

  • Hero Member
  • *****
  • Posts: 799
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #3 on: September 23, 2023, 01:18:02 pm »
Now the question is weither somebode can help me out debugging this to pieces of pascal code. So it displays text on my lcd_hd44780 display. From the left MCU to the right MCU
Just to confirm, it seems as if you are trying to transmit data from an atmega (left channel) to another atmega (right channel) and then display the data received on the right channel to an HD44780 LCD, is that correct?

If so, the right channel should run as an i2c slave.  The TI2CMaster (as the name suggest) can only handle master transactions, in other words it can only handle communication with a slave device.  At the moment the fpc-avr library doesn't have an i2c slave example.  I will see what I can piece together this weekend.

Do you use the right channel just to display data over i2c on an LCD?  If so, consider an i2c backpack for the LCD. There is an existing library for this.

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #4 on: September 23, 2023, 01:23:18 pm »
Thank you Mr ccrause, that would be great help! Some I2C Slave code . Waiting for that.
« Last Edit: September 23, 2023, 01:29:38 pm by pascalbythree »

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #5 on: September 25, 2023, 10:49:12 am »
Still waiting for my super project  :o

ccrause

  • Hero Member
  • *****
  • Posts: 799
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #6 on: September 25, 2023, 08:26:04 pm »
An interrupt driven I2C slave library with a simple demo program. Very little testing was done, and that only via the demo program. The demo should be a good starting point for an I2C slave that dumps received bytes to an LCD.

Edit: added link to demo.
« Last Edit: September 26, 2023, 07:13:47 pm by ccrause »

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #7 on: September 26, 2023, 01:11:32 pm »
Thank you, now i can start coding again, you will hear from me soon.  8-)

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #8 on: September 26, 2023, 02:14:59 pm »
Earthly bless you! It got to work! Thank you Mr CCrause and other forum people!

Now i can continue for years!

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #9 on: September 27, 2023, 02:05:40 pm »
ohhh ohh, more trouble !

Is it possible to send a byte from the I2C Slave to the I2C MASTER ?

Does mr CCrause also have example code to do it backwards ? Greets, Wouter van Wegen PascalByThree !

For the rest everything seems to work.  8-)

ccrause

  • Hero Member
  • *****
  • Posts: 799
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #10 on: September 27, 2023, 06:18:51 pm »
Is it possible to send a byte from the I2C Slave to the I2C MASTER ?
Only if the I2C master requests the data.  The I2C slave can not initiate communication. Can you describe the overall communication flow, when does which side need to transmit data?

If you want bidirectional control over I2C:
a) Run both controllers in I2C slave mode (to listen for requests)
b) When one controller needs to send data, switch to master mode, perform I2C transaction, then switch back to slave mode

In theory you can do this with the existing master and slave libraries, but managing the global interrupt flag is important since only the slave mode expects interrupts. You can check if the following pseudocode works for your situation (untested!):
Code: Pascal  [Select][+][-]
  1. begin
  2.   i2cslave_listen(thisaddress, ...);
  3.   repeat
  4.     // Perform routine tasks here while waiting for either an I2C message
  5.     // or something to to transmit to other controller
  6.  
  7.     if (something important to transmit to other controller) then
  8.     begin
  9.       i2cslave_stop;
  10.       i2c_master.init(I2C_50kHz);
  11.       if i2c_master.start(otheraddress, I2C_WriteMode) then
  12.       begin
  13.         i2c_master.writeByte(x);
  14.         i2c_master.stop;
  15.       end;
  16.       i2cslave_listen(thisaddress, ...);
  17.     end;
  18.   until false;
  19. end.

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #11 on: September 28, 2023, 02:47:33 pm »
Working on it. You will hear back from me soon!

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #12 on: September 30, 2023, 07:16:42 pm »
i2c.pas

Code: Pascal  [Select][+][-]
  1.   // atmega4809 default TWI pins
  2. {$if defined(CPUAVRXMEGA3)}
  3.   {$define SCLpin := 3}
  4.   {$define SCLpin_bm := (1 shl SCLpin)}
  5.   {$define SCLport := PORTA}
  6.   {$define SDApin := 2}
  7.   {$define SDApin_bm := (1 shl SDApin)}
  8.   {$define SDAport := PORTA}
  9. {$elseif defined(FPC_MCU_ATMEGA328P)}
  10.   {$define SCLpin := 5}
  11.   {$define SDApin := 4}
  12.   {$define SDApin_bm := (1 shl SDApin)}
  13.   {$define SCLpin_bm := (1 shl SCLpin)}
  14.   {$define I2Cport := PORTC}
  15.   {$define I2CDDR := DDRC}
  16.   {$define I2CPins := PINC}
  17. {$else}
  18.   {$error 'MCU is not an XMEGA3 or atmega328p'}
  19. {$endif}

I just finished, setting up my breadboard with a Atmega16A and a LCD on it.

In the mean while i have to know, what values to change to test the I2C en i2C slave unit on the Atmega16A

Can somebody change them for me ? Greet, PascalByThree, Wouter van Wegen

After that i probably will respond with some more questions left...

« Last Edit: September 30, 2023, 07:33:08 pm by pascalbythree »

pascalbythree

  • Full Member
  • ***
  • Posts: 243
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #13 on: September 30, 2023, 07:32:38 pm »
Code: Pascal  [Select][+][-]
  1.   {$define SCLpin := 0}
  2.   {$define SDApin := 1}
  3.   {$define SDApin_bm := (1 shl SDApin)}
  4.   {$define SCLpin_bm := (1 shl SCLpin)}
  5.   {$define I2Cport := PORTC}
  6.   {$define I2CDDR := DDRC}
  7.   {$define I2CPins := PINC}

Is this sufficient ?

ccrause

  • Hero Member
  • *****
  • Posts: 799
Re: Large system, i2C to go with Freepascal on AVR, code help
« Reply #14 on: September 30, 2023, 08:52:34 pm »
Code: Pascal  [Select][+][-]
  1.   {$define SCLpin := 0}
  2.   {$define SDApin := 1}
  3.   {$define SDApin_bm := (1 shl SDApin)}
  4.   {$define SCLpin_bm := (1 shl SCLpin)}
  5.   {$define I2Cport := PORTC}
  6.   {$define I2CDDR := DDRC}
  7.   {$define I2CPins := PINC}

Is this sufficient ?

Yes, those are correct for the atmega16.

 

TinyPortal © 2005-2018