Ада i2c демо на микробите с библиотекой драйверов Ада? - PullRequest
1 голос
/ 08 октября 2019

Обзор: Я пытаюсь запрограммировать микробит с помощью Ada с помощью библиотеки драйверов Ada и не могу понять, как использовать функции i2c для установления связи с другим чипом. Я хотел бы создать простую демонстрацию, чтобы я мог понять, что происходит, потому что демонстрации в каталоге компонентов библиотеки драйверов Ada идут мне на голову (я тоже довольно новичок в Ada, и это не помогает вопросам).

Простейшая демонстрация i2c в библиотеке драйверов Ada, по-видимому, предназначена для трехосного компаса AK8963 (находится в / components / src / motion / ak8963 /). Но это все еще идет мне в голову, и у меня нет чипа для запуска и отладки кода.

Вот что я попробовал: Я создал две разные демонстрации с Arduinos,В обеих демонстрациях передатчик отправляет «A», а затем «B» до «Z», а затем возвращается к «A». В первой демонстрации ведущий передает следующий символ каждые 500 мс, а ведомый получает его. И во второй демонстрации мастер запрашивает следующий символ каждые 500 мс, и ведомый передает его.

Мои демо-версии взяты из примеров Arduino Wire здесь и здесь .

Ответы [ 3 ]

1 голос
/ 19 октября 2019

Я понял.

Давайте начнем с двух программ Arduino, чтобы доказать, что код Arduino работает.

Передача Arduino Slave:

/*
Sends the next letter of the alphabet with each
request for data from master.

Watch the serial monitor to see what's happening.
*/

#include <avr/wdt.h>
#include <Wire.h>

// A note about I2C addresses.
// The Ada program is looking for the slave on address 16
// but this code says the slave is on 8.
// What's happening? As best as I can tell it works
// like this:
// 16 in binary is 10000. But arduino strips the read/write bit 
// (which is the last bit) off of the address so it becomes 
// 1000 in binary. And 1000 in binary is 8.
const int SLAVE_ADDRESS = 8;
byte letter = 65; // letter A
unsigned long counter = 0;

void setup()
{
  wdt_reset();
  wdt_enable(WDTO_8S);

  Serial.begin(9600);
  Serial.println("beginning");

  Wire.begin(SLAVE_ADDRESS);        // join i2c bus
  Wire.onRequest(requestEvent);     // register event
}

void loop()
{
  wdt_reset();
  counter++;
  if(counter % 1000 == 0)
  {
    // Display a heart beat so we know the arduino has not hung.
    Serial.print("looping: ");
    Serial.println(counter);
  }
  delay(5);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  // send the current letter on I2C
  Wire.write(letter);

  Serial.print("transmitting: ");
  Serial.println(char(letter));

  letter++;
  if(letter > 90) // if greater than Z
  {
    letter = 65; // reset to A
  }
}

Мастер Arduino получает:

/*
Requests a character from the slave every 500 ms and prints it
to the serial monitor.
*/

#include <avr/wdt.h>
#include <Wire.h>

const int SLAVE_ADDRESS = 8;

void setup()
{
  wdt_reset();
  wdt_enable(WDTO_8S);
  Wire.begin();        // join i2c bus
  Serial.begin(9600);
}

void loop()
{
  // reset the watchdog timer
  wdt_reset();

  // request one byte from the slave
  Wire.requestFrom(SLAVE_ADDRESS, 1);

  while(Wire.available()) // slave may send less than requested
  {
      // receive a byte as character
    char c = Wire.read();
    Serial.println(c);
  }
  delay(500);
}

Эти два эскиза Arduino будут с радостью передавать персонажей весь день. Теперь замените главный приемник Arduino на версию Ada ниже и физически отключите главный приемник Arduino.

Главный приемник Ada (main.abd):

--  Request a character from the I2C slave and
--  display it on the 5x5 display in a loop.

with HAL.I2C;          use HAL.I2C;
with MicroBit.Display; use MicroBit.Display;
with MicroBit.I2C;
with MicroBit.Time;

procedure Main is
   Ctrl   : constant Any_I2C_Port := MicroBit.I2C.Controller;
   Addr   : constant I2C_Address := 16;
   Data   : I2C_Data (0 .. 0);
   Status : I2C_Status;
begin

   MicroBit.I2C.Initialize (MicroBit.I2C.S100kbps);
   if MicroBit.I2C.Initialized then
      --  Successfully initialized I2C
      Display ('I');  
   else
      --  Error initializing I2C
      Display ('E');  
   end if;
   MicroBit.Time.Delay_Ms (2000);
   MicroBit.Display.Clear;

   loop
      --  Request a character
      Ctrl.Master_Receive (Addr => Addr, Data => Data, Status => Status);

      --  Display the character or the error
      if Status = Ok then
         Display (Character'Val (Data (0)));
      else
         MicroBit.Display.Display (Status'Image);
      end if;

      --  Give the user time to read the display
      MicroBit.Time.Delay_Ms (1000);
      MicroBit.Display.Clear;
      MicroBit.Time.Delay_Ms (250);
   end loop;
end Main;

А вот файл проекта Ada для полноты:

with "..\..\Ada_Drivers_Library\boards\MicroBit\microbit_zfp.gpr";

project I2C_Master_Receive_Demo is

   for Runtime ("ada") use Microbit_Zfp'Runtime ("Ada");
   for Target use "arm-eabi";
   for Main use ("main.adb");
   for Languages use ("Ada");
   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Create_Missing_Dirs use "True";

   package Compiler renames Microbit_Zfp.Compiler;

   package Linker is
      for Default_Switches ("ada") use Microbit_Zfp.Linker_Switches & ("-Wl,--print-memory-usage", "-Wl,--gc-sections", "-U__gnat_irq_trap");
   end Linker;

   package Ide is
      for Program_Host use ":1234";
      for Communication_Protocol use "remote";
      for Connection_Tool use "pyocd";
   end Ide;

end I2C_Master_Receive_Demo;

Советы:

  • вам необходимо соблюдать I2Cсмещения адреса (16 в Ada = 8 на Arduino в моем случае). См. Объяснение в комментариях к ведомому коду передачи Arduino выше. Мне потребовалось много времени, чтобы понять это.
  • ничего не работало с тремя устройствами, подключенными к шине I2C , даже если одно из них не было запитано. Я не знаю точно, что там происходит, но я подозреваю, что это связано с документацией, в которой говорится, что шина I2C не может вернуть свои линии обратно в HIGH. В некоторых документах рекомендуется размещать резистор на обеих линиях I2C, подключенных к напряжению вашего источника, чтобы линейные напряжения возвращались к ВЫСОКОМУ после того, как устройства понижают их.
  • эта работа будет проще с осциллографом . Я мог бы решить эту проблему намного быстрее, если бы у меня была такая проблема.
0 голосов
/ 17 октября 2019

У меня есть текущий интерес к BBC micro: bit и i2c, и я попробовал программу, предварительно получив программу для успешной сборки и загрузки. Сборка с этими двумя файлами должна была быть проще, до сих пор не получилось ее собрать, борется с GPS ... Попробую еще раз скоро ...

0 голосов
/ 09 октября 2019

Я не смог протестировать приведенный ниже код, но он, по крайней мере, должен дать вам некоторое указание. Обратите внимание, что micro: bit действует как мастер. Я не думаю, что micro: bit может выступать в роли раба на шине I2C (но я могу ошибаться здесь). Также обратите внимание, что вам, возможно, придется изменить путь к microbit_zfp.gpr в файле проекта.

default.gpr

with "../Ada_Drivers_Library/boards/MicroBit/microbit_zfp.gpr";

project Default is

  for Runtime ("ada")      use MicroBit_ZFP'Runtime ("Ada");
  for Target               use "arm-eabi";
  for Main                 use ("main.adb");
  for Languages            use ("Ada");
  for Source_Dirs          use ("src");
  for Object_Dir           use "obj";
  for Create_Missing_Dirs  use "True";

  package Compiler renames MicroBit_ZFP.Compiler;

  package Linker is
     for Default_Switches ("Ada") use
       MicroBit_ZFP.Linker_Switches &
       ("-Wl,--print-memory-usage",
        "-Wl,--gc-sections",
        "-U__gnat_irq_trap");
  end Linker;

end Default;

main.adb

with MicroBit.Display; use MicroBit.Display;
with MicroBit.Time;    use MicroBit.Time;
with MicroBit.I2C;     use MicroBit.I2C;
with HAL.I2C;          use HAL.I2C;

procedure Main is
begin

   MicroBit.I2C.Initialize (S400kbps);   --  Change to desired speed.

   declare    
      Ctrl   : constant Any_I2C_Port := MicroBit.I2C.Controller;
      Addr   : constant I2C_Address := 16#08#;    --  Change to correct address.
      Data   : I2C_Data (0 .. 0);
      Status : I2C_Status;
   begin
      loop

         --  Data to be send (here: character 'x').
         Data (0) := Character'Pos ('x');

         --  Display a dot to indicate where we are.
         Display ('.');

         --  Send 1 byte of data (length of Data array is 1).
         Ctrl.Master_Transmit (Addr, Data, Status);

         --  Additional status checking could be done here....

         --  Display a colon to indicate where we are.
         Display (':');

         --  Wait for response (1 byte as the length of the Data array is 1).         
         Ctrl.Master_Receive (Addr, Data, Status);

         --  Check status, and display character if OK.
         if Status = Ok then
            Display (Character'Val (Data (0)));
         else
            Display ('!');
         end if;

         -- Take a short nap (time in milliseconds).
         Sleep (250);

      end loop;
   end;

end Main;
...