реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Slave HAL FreeRTOS, Эмуляция ds1307
simark1979
сообщение Feb 6 2018, 21:16
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 14-03-09
Из: Краснодарский край
Пользователь №: 46 094



Доброе время суток)

Извините за наглость rolleyes.gif но вопрос общего характера.

Мне нужно написать эмуляцию часов ds1307.
Понятно, что это будет slave, с командами чтения и записи по i2c
Никак в голове никак не складывается концепция реализации на FreeRTOS (имеется ввиду взаимодействие коллбэков и потоков, как распознать команды чтения/записи)

На картинке, пример работы с ds1307:
packet#27 - так происходит запись (первый байт куда писать, остальные что писать)
packet#28 - установка указателя для чтения
packet#29 - чтение данных

Вообщем протокол стандартный.
Прикрепленное изображение


Может у кого-то есть опыт или идеи по написанию слэйва под операционкой?
Буду рад любой помощи)

Сообщение отредактировал simark1979 - Feb 7 2018, 11:41
Go to the top of the page
 
+Quote Post
simark1979
сообщение Feb 7 2018, 18:35
Сообщение #2


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 14-03-09
Из: Краснодарский край
Пользователь №: 46 094



Товарищи, помогите плиз подступится к реализации


Я или устал или это действительно сложно, но никак не могу найти правильный подход к реализации протокола внутри RTOS и HAL.

Хоть бы пиночек мне)
Go to the top of the page
 
+Quote Post
juvf
сообщение Feb 8 2018, 09:01
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



Не понятно в чем вопрос? В эмуляции i2c, или в эмуляции ds1307?

раз не указываете мк, то подразумевается, что аппаратного i2c слейва на борту нет и вам нужен ногодрыг?

Ногодрыг можно так реализовать:
из даташита на ds1307 SCL на максимальной частоте (100 кГц). Один так на и2ц 0,01 мс. Про реализацию такого ногодрыга средствами ртос - забудьте. Обычно у ртос системный тик 1 мс.

Нужно делать на прерываниях: GPIO + TIM. Делайте глобальные переменные, в которых размешаете текущее состояние и2ц, текущий номер бита, адреса, команды и т.п.

Изначально текущее состояние и2ц ESTABLISHED. Ловите прерывание на SCL по заднему фронту, если при этом на SDA было лог "1", то состояние меняете на "Ожидание tHD:STA". Запускаете таймер ждете.... если сработало прерывание на SDA 1-0, то был старт. Если сработал таймер, то возвращаетесь в ESTABLISHED (ожидание старта).
если был старт, то запускаете таймер на ожидание фронта 0-1 на CLK, меняете состояние на "ожидание первого байта адреса". Пришло прерывание 0-1 на CLK - читаете SDA. Таймер перезапускаете на ожидание 1-0 на SCL..... и т.д. Т.о. весь протокол реализуете.... Там, где слейв должен дать АСК, меняете направление порта и дает "0".
По приему Stop можно в RTOS выстовить флаг/евент из прерывания о полученных данных. Задача ожидает флаг/евент.... по флагу разблокируется и обработает данные.

Эмуляция ds1307 - тут что не понятно? Заводите структуру как Карта aдресов, что типа такой
Код
typedef union  
{
    struct
      {
          uint8_t sec;
        uint8_t min;
        uint8_t hour;
        uint8_t week;
                uint8_t day;
        uint8_t mount;
                uint8_t year;
                uint8_t control;
                uint8_t array[56];
      }mem;
      uint8_t data[64];
} ds1307Mem;


Цитата
packet#27 - так происходит запись (первый байт куда писать, остальные что писать)

* приходит от мастера к слейву старт условие,
* 7 бит адреса Addr,
* 1 бит команды WRITE,
* слейв передает ACK ( переводит порт SDA в OUT и выдает 0, затем опять переводит порт в in),
* мастер передает в слейв 1-ый байт,
* слейв выдает аск,
* мастер передает в слейв 2 байт,
* слейв выдает аск,
* мастер передает в слейв 3 байт,
* слейв выдает аск,
* мастер передает в слейв 4 байт,
* слейв выдает аск,
....
* мастер выдает стоп.

В прерывании при обнаружении STOP условия послать эвент в задачу о приеме n-байт, которые нужно записать по указателю &ds1307Mem.data[Addr]. Естественно проверяем выход Addr за пределю массива ds1307Mem.data[].
Обрабатываем ds1307Mem.mem.control, если вы эмулирете Output control.
Для кошерности запускаем ещё один таймер или же в задаче системного тика эмулируем счет времени и меняем по мере изменения времени данные в ds1307Mem. как-то так.
Go to the top of the page
 
+Quote Post
simark1979
сообщение Feb 8 2018, 10:16
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 14-03-09
Из: Краснодарский край
Пользователь №: 46 094



Спасибо Вам, что откликнулись.

Извините, что не указал камень (подумал, что для HAL это несущественно)
Камень stm32f407 конечно же там аппаратный i2c
Сейчас как Вы и предлагаете, прихожу к выводу, что HAL тут неуместен и нужен низкий уровень, но возможно ошибаюсь.

У меня вопрос был по реализации протокола именно на HAL_I2C

Понятно, как ловить генерацию СтартАдрес/Режим w/r со стороны мастера. Для этого есть HAL_I2C_AddrCallback()

Но нет понимания в следующем:
Как заставить HAL принять данные от мастера переменной длинны? Все функции HAL_I2C_Slave_Recieve* требую передать количество ожидаемых байт
Либо/и
Как ловить очередной принятый от мастера байт для анализа?
UPD: как поймать Stop.

Реализация HAL Slave, очень ограничена, или я чего-то не догоняю?

Сообщение отредактировал simark1979 - Feb 8 2018, 10:47
Go to the top of the page
 
+Quote Post
juvf
сообщение Feb 8 2018, 11:32
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 261
Регистрация: 14-05-09
Из: Челябинск
Пользователь №: 49 045



с халом HALом косяк. См исходники
В блокирующем чтении да, не выйдем из приема, пока не получим нужное кол-во байт, либо по таймауту.
в неблокирующем режиме по прерываниям, тут ворде можно можно получить переменное кол-во байт.
Вызывайте HAL_I2C_Slave_Receive_IT(hi2c, pData, 255);
на сколько я понял, в обработчике прерывания не контролируется размер принятых байт.
хал в прерывании автоматом будет ловить принятые байты и стоп.
После появления STOP-условия прием завершиться и будет вызвана функция void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c).
Определите у себя в коде void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c). Кол-во принятых байт 255 - hi2c->XferSize. Из неё отправляйте в таск эвент/флаг/сигнал/мессадж...


ps на сколько я понял, если вызвать HAL_I2C_Slave_Receive_IT(hi2c, pData, 2);, а мастер передаст больше 2-х байт, стрельните себе HAL выстрелит вам в ногу.
Go to the top of the page
 
+Quote Post
simark1979
сообщение Feb 8 2018, 12:50
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 14-03-09
Из: Краснодарский край
Пользователь №: 46 094



Цитата(juvf @ Feb 8 2018, 14:32) *
с халом HALом косяк. См исходники
В блокирующем чтении да, не выйдем из приема, пока не получим нужное кол-во байт, либо по таймауту.
в неблокирующем режиме по прерываниям, тут ворде можно можно получить переменное кол-во байт.
Вызывайте HAL_I2C_Slave_Receive_IT(hi2c, pData, 255);
на сколько я понял, в обработчике прерывания не контролируется размер принятых байт.
хал в прерывании автоматом будет ловить принятые байты и стоп.
После появления STOP-условия прием завершиться и будет вызвана функция void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c).
Определите у себя в коде void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c). Кол-во принятых байт 255 - hi2c->XferSize. Из неё отправляйте в таск эвент/флаг/сигнал/мессадж...


ps на сколько я понял, если вызвать HAL_I2C_Slave_Receive_IT(hi2c, pData, 2);, а мастер передаст больше 2-х байт, стрельните себе HAL выстрелит вам в ногу.


Действительно, по получению меньшего количества данных, приём заканчивается, но вызова HAL_I2C_SlaveRxCpltCallback увы нет, проверил

Так что видимо придется использовать LL драйвер

Go to the top of the page
 
+Quote Post
simark1979
сообщение Feb 8 2018, 14:03
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 14-03-09
Из: Краснодарский край
Пользователь №: 46 094



А вы никогда не пробовали в Кубе включить для i2c LL драйвер, вместо HAL?

Тут какое-то чудо)
Я так и не врубился, но слэйв заработал сам собой, своего кода я совершенно не добавлял.


Вот так куб мне сгенерил инициализацию:
Код
void MX_I2C2_Init(void)
{
  LL_I2C_InitTypeDef I2C_InitStruct;

  LL_GPIO_InitTypeDef GPIO_InitStruct;
  
  /**I2C2 GPIO Configuration  
  PF0   ------> I2C2_SDA
  PF1   ------> I2C2_SCL
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_0|LL_GPIO_PIN_1;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
  LL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C2);

    /**I2C Initialization
    */
  LL_I2C_DisableClockStretching(I2C2);

  I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
  I2C_InitStruct.ClockSpeed = 100000;
  I2C_InitStruct.DutyCycle = LL_I2C_DUTYCYCLE_2;
  I2C_InitStruct.OwnAddress1 = 208;
  I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
  I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
  LL_I2C_Init(I2C2, &I2C_InitStruct);

  LL_I2C_SetOwnAddress2(I2C2, 0);

  LL_I2C_DisableOwnAddress2(I2C2);

  LL_I2C_DisableGeneralCall(I2C2);

}


Кроме инициализации я ничего не делаю, но после этого у меня лог анализатор начал ловить ответы по шине sm.gif

Cлэйв начал отвечать: забирает и отдает данные (но пока непонятно что это за данные)
И непонятно, каким образом это работает при отключенном в Кубе прерываний для I2C2 или в МК реализован полный аппаратный slave автомат.... blink.gif

Сообщение отредактировал simark1979 - Feb 9 2018, 13:45
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
simark1979
сообщение Feb 9 2018, 21:32
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 14-03-09
Из: Краснодарский край
Пользователь №: 46 094



Вобщем написал я эмулятор)

Для i2c slave подобного типа получилось написать только на LL, HAL оказался непригоден.

В сети на LL примеров практически нет, поэтому примеры ищите в \STM32Cube_FW_L4_V1.11.0\Projects\NUCLEO-L476RG\Examples_LL\
Там много чего есть)

Вопрос закрыт, всем спасибо)

Сообщение отредактировал simark1979 - Feb 9 2018, 21:33
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 16th April 2024 - 06:24
Рейтинг@Mail.ru


Страница сгенерированна за 0.01435 секунд с 7
ELECTRONIX ©2004-2016