Ник:
Пароль:

Контакты

E-mail: info@starterkit.ru
тел.: +7 922 680-21-73
тел.: +7 922 680-21-74
Телеграм: t.me/starterkit_ru
Партнеры:
otladka.com.ua - г.Киев

Способы оплаты

User Info


Добро пожаловать,
Guest

Регистрация или входРегистрация или вход
Потеряли пароль?Потеряли пароль?

Ник:
Пароль:

ПользователейПользователей:1
Поисковых ботовПоисковых ботов:2
ГостейГостей:1

ОбновитьПодробнееВсегоВсего:4
Форум » starterkit.ru » Embedded Linux
Chip Select Decoding на AT91
Lampus
Добавлено 20.05.2011 12:14
0
Сообщение: 1
Lampus
5

Пункты: 3552
Регистрация: 26.04.2011
Приветствую.
Случилось так, что появилась необходимость навесить на одну шину SPI 9 устройств. Вычитал в даташите на AT91SAM9260 что он поддерживает функцию Chip Select Decoding при использовании внешней логики для декодирования. В принципе это то, что мне надо. Но самим драйвером atmel_spi данная функция не поддерживается, к тому же там вмсето аппаратных NCPS используются GPIO-пины (из-за аппаратного бага в старой версии кристалла), что для меня даже лучше, т.к. мне надо иметь CS-пины на разъёме.
Недолго думая прилепил нужный функционал с помощью костылей и подпорок.
Проблема в том, что массив пинов указывается в at91sam9260_devices.c, а функции активации/деактивации cs_[de]activate находятся в /drivers/spi/atmel_spi.c. Пришлось туда тащить копию массива пинов, что, мягко выражаясь, нехорошо и неправильно. В эти функции передаётся только один пин, который надо дёрнуть. Через поле npcs_pin структуры atmel_spi_device, которая в свою очередь передаётся в поле controller_data структуры spi_device. В одном из списков рассылки увидел предложение использовать controller_data для передачи необходимых параметров, например, указателя на функцию в файле at91sam9260_devices.c, откуда имеется доступ к массиву пинов. А теперь главное, вопросы:
1) Как реализовать данную функцию _правильно_ и более универсально? Можно ли использовать controller_data для передачи, скажем, массива пинов?
2) В функции cs_deactivate есть комментарий, который меня сильно смущает:
Код
/* only deactivate *this* device; sometimes transfers to
* another device may be active when this routine is called.
*/

Что с этим можно сделать?
3) В Kconfig-е сделал себе подменю "Chip Select Decoding" зависящее от SPI_ATMEL с конфигами "Enable Chip Selct Decoding on SPI bus 0" и "Enable Chip Selct Decoding on SPI bus 1". Проблема в том что на eMPU может быть разное кол-во SPI.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 20.05.2011 12:54 Редактировалось 20.05.2011 12:57 Сообщение: 2
sasamy
4.70

Пункты: 77067
Регистрация: 14.08.2009
Помоему задача решается тривиально - увеличением размера массива до нужного количества CS. Например для spi0
http://lxr.free-electrons.com/source/arch/arm/mach-at91/at91sam9260_devices.c#L548

static const unsigned spi0_standard_cs[9] = { перечисляем, тут, все, 9, gpio, для, которые, мы, выбрали в качестве CS };

Далле в
http://lxr.free-electrons.com/source/arch/arm/mach-at91/board-sam9260ek.c#L126

добавляем эти 9 устройств. Все. Никакие копии никуда таскать не надо ;-)
Спуститься к концу Подняться к началу
Персональная информация
Lampus
Добавлено 20.05.2011 14:32 Редактировалось 20.05.2011 14:33 Сообщение: 3
Lampus
5

Пункты: 3552
Регистрация: 26.04.2011
sasamy, это всё понятно, но у меня и так ног на разъёме не хватает. Мне нужен именно Chip Select Decoding и никак иначе. Нужно слепить плату расширения для существующего dev. board-а. Своя standalone железяка будет городится уже позже, а сейчас нужно уместится в пины на разъёме, хоть убейся.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 20.05.2011 15:44 Редактировалось 20.05.2011 15:47 Сообщение: 4
sasamy
4.70

Пункты: 77067
Регистрация: 14.08.2009
Надо было сразу сказать что gpio не хватает - сейчас все ясно и опять же задача тривиально решается :) Вместо одного gpio в каждом элементе массива:
static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PC11, AT91_PIN_PC16, AT91_PIN_PC17 };

хранить 4, например

#define CS_1 (AT91_PIN_PA3)
#define CS_2 (AT91_PIN_PC11 << 8)
#define CS_4 (AT91_PIN_PC16 << 16)
#define CS_8 (AT91_PIN_PC17 << 24)

static const unsigned int spi0_standard_cs[9] = {
CS_1,
CS_2,
CS_2 | CS_1,
CS_4,
CS_4 | CS_1,
CS_4 | CS_2,
CS_4 | CS_2 |CS_1,
CS_8,
CS_8 | CS_1,
};

и поправить ф-ции cs_activate/cs_deactivate
например вместо
gpio_set_value(asd->npcs_pin, active);

for (i = 0; i < 32; i += 8)
if ((asd->npcs_pin >> i) & 0xff)
gpio_set_value((asd->npcs_pin >> i) & 0xff, active);

номер GPIO не превышает 256, точнее максимальный номер = 32 + 32 *5 = 192
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 20.05.2011 15:56 Редактировалось 20.05.2011 16:23 Сообщение: 5
sasamy
4.70

Пункты: 77067
Регистрация: 14.08.2009
Причем в моем варианте будет обратная совместимость с тем как у атмелей сделано - можно им патч отправить ;-)
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 21.05.2011 10:47 Редактировалось 21.05.2011 11:03 Сообщение: 6
sasamy
4.70

Пункты: 77067
Регистрация: 14.08.2009
Цитата

2) В функции cs_deactivate есть комментарий, который меня сильно смущает:

Код
/* only deactivate *this* device; sometimes transfers to
* another device may be active when this routine is called.
*/

Что с этим можно сделать?


Если использовать стандартное поведение (которое используется в Linux по умолчанию) такая ситуация никогда не возникнет. Поясню расширенно :)
1 Все сообщения (spi_message http://lxr.free-electrons.com/source/include/linux/spi/spi.h#L452) не передаются в устройства немедленно а ставятся в очередь сообщений
2 Сообщения содержат от 1 до нескольких трансферов (spi_transfer http://lxr.free-electrons.com/source/include/linux/spi/spi.h#L365)
3 Стандартное поведение такое - перед передачей нового сообщения устройство активируется, после передачи трансфера - если трансфер последний в списке текущего сообщения, устройство деактивируется, если нет то устройство остается выбранным между трансферами текущего сообщения.
4 Стандартное поведение можно изменить - можно дективировать устройство после каждого трансфера и можно оставлять его активным после передаче последнего трансфера в сообщении.
И вот тут появляются грабли если на шине висит не одно устройство а несколько. Никто не гарантирует что все сообщения для одного устройства будут стоять в очереди подряд - в очереди они могут чередоваться для разных устройств - фрагментация неизбежна (при этом с трансферами одного сообщения такого никогда не будет - они передаются строго друг за другом для одного сообщения). При этом если в первом сообщении оставить после передачи устройство с активным CS а в очереди вопреки ожиданиям следующим будет сообщение для другого устройства - второе сообщение словят оба активных на данный момент устройства. Если использовать стандартное поведение - такого не произойдет, после передачи всех трансферов устройство деактивируется и не важно для кого второе сообщение - все пройдет четко по адресу.
Спуститься к концу Подняться к началу
Персональная информация
Lampus
Добавлено 23.05.2011 10:49 Сообщение: 7
Lampus
5

Пункты: 3552
Регистрация: 26.04.2011
sasamy, вот в том то вся и проблема. Есть у меня АЦП, для которого нужно держать CS активным после запуска конверсии, иначе нихрена он не сконвертит. То бишь для этой железки требуется держать CS активным на протяжении всего времени конверсии. АЦП точный 20-битный, при том весьма медленный, всего лишь около девяти сэмплов в секунду.
Что касается задумки с передачей всех пинов требующих активации в npcs_pin, то идея весьма хороша, это понятно и прозрачно. Но тут вылезают другие грабли.
1) В функции at91_add_device_spi нужно выставлять gpio используемые для cs как output'ы. (at91_set_gpio_output(cs_pin, 1);) Тут получается что в npcs_pin сразу несколько пинов, поэтому проще установить сразу все пины в массиве как выходы.
2) В функции atmel_spi_setup есть такой код:
Код

ret = gpio_request(npcs_pin, dev_name(&spi->dev));
if (ret) {
kfree(asd);
return ret;
}

Получается что один и тот же пин может быть использован для активации разных устройств, посему gpio_request будет возвращать -EBUSY. Пока я это решил тупо закомментив данный блок.
3) В связи с тем, что необходим режим удерживания CS, то в cs_deactivate лучше деактивировать все пины. А оттуда получить список всех пинов при таком подходе невозможно.
Просто в случае передачи в npcs_pin только тех пинов, которые нужно деактивировать, можно получить ситуацию когда будет активна передача к другому устройству, в итоге CS встанет чёрт знает в каое состояние.
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 23.05.2011 11:06 Сообщение: 8
sasamy
4.70

Пункты: 77067
Регистрация: 14.08.2009
1), 2) - я просто не стал расписывать подробней и не ошибся - вы сами все поняли :)

Цитата

3) В связи с тем, что необходим режим удерживания CS, то в cs_deactivate лучше деактивировать все пины.


Вот это не распарсил честно говоря - помоему это деление на ноль :) Вообще если есть такое медленное устройство вешать его на общую шину из 9 устройств - утопия, он будет ловить все сообщения на шине так как будет по сути постоянно активен - если вас это устраивает тогда сажаете его CS аппаратно на 0 и дело с концом, к тому же с CS decode в общем случае невозможно как вы правильно заметили держать одно устройство постоянно активным - там черте что получится.
Спуститься к концу Подняться к началу
Персональная информация
Lampus
Добавлено 23.05.2011 11:27 Сообщение: 9
Lampus
5

Пункты: 3552
Регистрация: 26.04.2011
sasamy, на самом деле не всё так страшно, этот АЦП должен отрабатывать лишь один раз при включении железяки, для того чтобы получить аддитивную составляющую погрешности при измерениях. Там можно и какой-нибудь костыль прилепить в виде натуральной задержки после запуска конверсии.
Я речь вёл про то, что если уж и сложится ситуация при которой cs_deactivate таки отработает уже после запуска cs_activate для железяки с другим CS, то лучше чтобы в cs_deactivate все пины используемы для выбора CS ставились в неактивное положение (никакое устройство не выбрано).
Спуститься к концу Подняться к началу
Персональная информация
sasamy
Добавлено 23.05.2011 11:43 Редактировалось 23.05.2011 11:47 Сообщение: 10
sasamy
4.70

Пункты: 77067
Регистрация: 14.08.2009
Цитата

этот АЦП должен отрабатывать лишь один раз при включении железяки


Вам видней что вам нужно, спорить/доказывать я ничего не собирался - описал ситуацию.

Цитата

Я речь вёл про то, что если уж и сложится ситуация при которой cs_deactivate таки отработает уже после запуска cs_activate для железяки с другим CS, то лучше чтобы в cs_deactivate все пины используемы для выбора CS ставились в неактивное положение (никакое устройство не выбрано).


Такая ситуация возможна только если настроить нестандартное поведение - после передачи сообщения оставлять устройство выбранным, если вы это решили использовать на общей шине из 9 устройств - СС3Б, в остальных случаях деактивировать все устройства на шине после каждого сообщения нет никакой надобности. Если по каким-то причинам вас не устраивает то что я описал - передавайте вместо cs указатель на свою ф-цию activate/deactivate как хотели сделать изначально - я ничего не имею против - вполне годный вариант :)
Спуститься к концу Подняться к началу
Персональная информация
Форум » starterkit.ru » Embedded Linux