ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Вторник
25 марта
1506594
Adept (17.03.2025 19:40 - 20.03.2025 19:19, просмотров: 4169)
тута на выходных чёт углУбился в смехотехнику, надо было сделать расширений портов для МК и на ввод и на вывод, чего-то потянуло на сладенькое параллельные шины, - сочинил 8-битныйую велосипед шину, мультиплицированную, шоб поменьше проводов.... камменты типа "мусье знает толк в извращениях" - принимаются :)) 

казалось бы - нафига, есть же spi, всего три лапы, да, оно так конечно и по скорости даже выигрывает, если линий не больше 16 (2 байта), а тут у меня до 256 линий на ввод, и стока же на вывод :) (ну я на макете сделал по 24 пока :)) пропускная способность на меге4809@20MHz с оптимизацией кода по скорости - 6,7Мбита (833-кило/сек) время одной транзакции, что на запись, что на чтение - 24 такта, и произвольный доступ к любой линии за это время (в отличие от цепочки регистров на SPI).

Вот сделал и думаю, - а надо ли?? :)) ну на самом деле прикольно получилось, да ещё аналоговый коммуттатор присобачил, шоб, когда шина в IDLE, можно было пользоваться другими функциями порта ШД.

Вот правда проектов, где мне нужно больше 20 I/O линий у меня немного :)

вот, в общем, может кому пригодицца :) Хоть там и тривиально всё, но самое интересное место - логика управляющих сигналов ALE;DLE;R/W

-------------------

для тех кому нехер делать интересно, - привожу сочинённый мной в бреду запале, текстовый каммент :))

P.S. выжал всё что cмог :) 6,7Мбит (близко к SPI)

;============================================================================
;uBUS_LIB.inc	библиотека процедур работы с мультиплицированной шиной uBUS
;
;Восьмибитная параллельная мультиплицированная (сначала выводим адрес IO-порта, потом записываем или считываем байт данных).
;Шина с тремя управляющими линиями + 8 линий данных (всего нужно 11 линий), после транзакции (24-30тактов ~1.2-1.5uS@20MHz
;в зависимости от оптимизации, по размеру или по скорости исполнения), шина "отпускается" переводится в состояние
;"RELEASE" (IDLE) и портом ШД можно пользоваться как угодно (в т.ч. и его альтернативными функциями).
;В "макси" варианте  м.б. до двух 16-битных дешифратора  адреса типа 74154, на блоке ввода и блоке вывода,
;и соответственно до 31 восьмибитных регистра ввода и столько же вывода, т.е. по 248 линий ввода и 248
;линий вывода (теоретически можно и больше, но на практике, незачем, даже 248 незачем :)
;248, потому что последний разряд дешифратора адреса нерабочий (там будут формироваться в некоторых случаях
;ложные сигналы, т.к. линии адреса дешифраторов подтянуты к 1.
;Как правило, можно вообще обойтись по одному восьмибитному битному дешифратору типа 74138, тогда будет
;по семь 8-битных портов ввода и столько де на вывод, т.е. по 56 линии на ввод и 56 линии на вывод,
;что на практике, более, чем достаточно.
;В некоторых случаях можно обойтись и без дешифраторов, тогда нужно задействовать отдельные линии управления
;для каждого IO-регистра и корректировать процедуры работы с шиной, но этот вариант тут пока не рассматривается.
;--
;дополнительно схемотехника шины подразумевает использование аналогового мультиплексора, для возможности работы
;ШД не в составе шины uBUS, а с альтернативными функциями портов, что позволяет иметь на шине, кроме стандартных
;цифровых IO линий, и другую периферию (определяемую альтернативными функциями порта).
;--
;Порт ШД (8бит) должен быть на одном из портов МК, линии управления шиной м.б. разбросаны по разным портам МК.
;------------------------
;шина uBUS имеет 11 линий:
;D0..D7 - восемь линий шины данных (ШД)
;ALE - строб адреса
;DLE - строб данных
;R/W - направление работы шины (чтение/запись)
;
;линия R/W определяет то, в каком режиме шина в данный момент.
;(нормальная ситуация у нас почти постоянная "1" на линии R/W.
; "0" там только во время вывода новых данных в порт шины (OUT-регистры))
;Время транзакции на шине - 1,2-1,5uS @CPU=20MHz
;
;пропускная способность шины (на atmega4809@20MHz) порядка
;  833кБайт/сек  (6.7МБит/с) при оптимизации по скорости исполнения кода
;  670кБайт/сек  (5.4МБит/с) при оптимизации по размеру кода
;
;процедура записи в порт:
;------------------------
;uBUS_OUT	;Вывод информации с "регистра данных" (ячейки памяти "S_uBUS_DATA") на шину uBUS (Out-порт)
; (время выполнения процедуры:
;	оптимизация "compact"	30 cycles / 1.5uS@20MHz)
;	оптимизация "fast"	24 cycles / 1.2uS@20MHz)
;~~~~~~~~~~~~~~~~~~~~~~~~
; - настраиваемся на запись в шину (сигнал R/W=0)
; - установка адреса порта
;	- запрещаем строб данных DLE=0
;	- переключение ШД на вывод и выводим на неё номера порта
;	- формируем строб записи адреса - короткий импульс ALE
;	  (на этот момент ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
; - вывод байта данных на ЩД
; - стробируем данные для записи на шину (эту функцию выполняет сигнал DLE)
; - освобождаем шину, т.е. переводим в состояние "RELEASE" (DLE="0", ALE = "0", R/W="1")
;------------------------
;процедура чтения из порта:
;uBUS_IN	;Ввод информации с шины (In-порта) в её "регистр данных" (ячейку памяти "S_uBUS_DATA")
; (время выполнения процедуры:
;	оптимизация "compact"	30 cycles / 1.5uS@20MHz)
;	оптимизация "fast"	24 cycles / 1.2uS@20MHz)
;~~~~~~~~~~~~~~~~~~~~~~~~
; - настраиваемся на запись в шину (сигнал R/W=0)
; - установка адеса порта
;	- запрещаем строб данных DLE=0
;	- переключение ШД на вывод и выводим на неё номера порта
;	- формируем строб записи адреса - короткий импульс ALE
;	  (на этот момент ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
; - переключаем ШД на чтение
; - установим сигнал R/W в "1"
; - стробируем данные считываемые во входные регистры (эту функцию выполняет сигнал DLE)
; - считываем данные с нужного регистра, который на этот момент подсоединён к ШД
; - освобождаем шину, установив DLE=0, т.е. переводим в состояние "RELEASE" (IDLE)
;   (т.к. на текущей момент DLE="0", ALE = "0", R/W="1" и ЩД настроена на ввод данных)
;
;НЕ ДОПУСКАЮТСЯ ВЛОЖЕННЫЕ ПРОЦЕДУРЫ РАБОТЫ С ШИНОЙ. все операции доступа к шине д.б. в одном цикле.
;-------
;библиотечка имеет два типа оптимизации (#define CodeOptimization)
;	- по скорости исполнения - fast
;	- по объёму кода - compact
;
;19/III.25.
;============================================================================


ежели альтернативные функции ШД не нужны, то коммутатор-дешифратор шины - 4 корпуса логики (инверторы, два дешифратора, параллельный регистр) и по одному регистру типа 573 на каждый дополнительный 8-битный порт, если нужны альтернативные функции порта ШД, то нуна добавить аналоговый мультиплексор и корпус логики 2и-не :)

вот и думайте теперь как энто развидеть :))


ну и собсна библиотечка :) /добавил сегодня треша оптимизацию по скорости или размеру, и соответсвующие дефайны и директивы условной компиляции :)/

оптимизация по скорости дала 25% прирост пропускной способности шины :) дотянул до цифры 6,7МБита (почти SPI, но зато произвольный доступ к любой линии порта :))

P.S. первоначальная версия из-за "излишеств нехороших всяких" имела в 2 раза меньшую скорострельность :) Здесь вроде оптимизировал по максимуму, и прикрутить можно к любому камню, от тайни до иксмеги практически без изменений. Можно конечно и стандартный SPI/I2C порт-экстендер присобачить, но с этим однозначно проще работать в ПО, а на какую-нить тайни на сях с готовыми либами не напишешься, да и с I2C там на ассемблерах разбираться не сахар не каждых захочет, и вот такое решение, может оказаться вполне к месту. Вот есть у меня к примеру много тайнь1616 - хороший камушек и памяти много, но прикрутил к нему несколько кнопок, с десяток сегментных индикаторов, и всё - ноги закончились :( а по функционалу (скорострельность, объём программы) его более, чем достаточно. А на I2C экстендеры у меня чёт совсем "не стоит" - достали меня кривой I2C автомат меги88 в прошлых проектах. потом в иксмеге ещё заводил, а там свои "погремушки" были. В общем какая-то у меня аллергия на I2C случилась :))



;----------------------------------------------------------------------------
// *** конфигурирование аппаратуры ПРОЕКТА для МК atmega4809
// необходимо использовать виртуальные порты, в противном случае процедуры будут практически вдвое длиннее

#define	uBUS_DATA_PortIN	VPORTD_IN	;регистр порта считывания данных
#define	uBUS_DATA_PortOUT	VPORTD_OUT	;регистр порта вывода данных
#define	uBUS_DATA_PortDIR	VPORTD_DIR	;регистр переключения направления порта данных

;линия R/W
#define	uBUS_RW_PortOUT		VPORTB_OUT
#define	uBUS_RW_PortDIR		VPORTB_DIR
#define	uBUS_RW_line		2		;Номер линии R/W

;линия ALE
#define	uBUS_ALE_PortOUT	VPORTB_OUT
#define	uBUS_ALE_PortDIR	VPORTB_DIR
#define	uBUS_ALE_line		5		;Номер линии ALE

;линия DLE
#define	uBUS_DLE_PortOUT	VPORTB_OUT
#define	uBUS_DLE_PortDIR	VPORTB_DIR
#define	uBUS_DLE_line		4		;Номер линии DLE
;
;============================================================================
// типы оптимизации (НЕ НАЗНАЧАТЬ НОЛЬ !!) - по скорости или размеру
#define	fast	1	;оптимизация кода по скорости выполнения
#define	compact	2	;оптимизация кода по размеру
;-- определение оптимизации процедур - по скорости исполнения или размеру кода
;	(нужно выбрать вариант из двух вышеприведённых)
#define	CodeOptimization	fast
;#define	CodeOptimization	compact
;----------------------------------------------------------------------------
#ifndef CodeOptimization
	#error	"uBUS_library need to optimization type assign"
#endif
.cseg
//библиотека процедур работы с мультиплицированной шиной uBUS
/*
----- внутренние процедуры
uBUS_RELEASE		;освобождение шины (можно работать с альтернативными функциями порта ШД)
uBUS_Config		;стартовая процедура настройки аппаратного окружения для работы с шиной uBUS
Set_uBUS_IO_Address	;Установка адреса IO регистра на шине
;
----- законченные библиотечные процедуры
uBUS_IN			;Ввод информации с шины (In-порта) в её "регистр данных" (ячейку памяти "S_uBUS_DATA")
 (время выполнения процедуры:
	оптимизация "compact"	30 cycles / 1.5uS@20MHz)
	оптимизация "fast"	24 cycles / 1.2uS@20MHz)
---
uBUS_OUT		;Вывод информации с "регистра данных" (ячейки памяти "S_uBUS_DATA") на шину uBUS (Out-порт)
 (время выполнения процедуры:
	оптимизация "compact"	30 cycles / 1.5uS@20MHz)
	оптимизация "fast"	24 cycles / 1.2uS@20MHz)
----------------
вне процедур записи/чтения работают альтернативные функции МК на линиях ШД
----------------
освобождение шины (можно работать с альтернативными функциями порта ШД)
(ALE=0, DLE=0, R/W=1)
*/
;
;19/III.25
;------------------------------------------------------------------------------
.macro	uBUS_RELEASE
#if	CodeOptimization == fast
	clr	TMP			;все линии ШД - направление "на ввод"
	out	uBUS_DATA_PortDIR,TMP
	;
	//Настроим данные для линии ALE=0; DLE=0; R/W=1 (состояние шины "RELEASE")
	cbi	uBUS_ALE_PortOUT,uBUS_ALE_line
	cbi	uBUS_DLE_PortOUT,uBUS_DLE_line
	sbi	uBUS_RW_PortOUT,uBUS_RW_line
#elif	CodeOptimization == compact
	rcall	uBUS_RELEASE_SUB
#else
	#error "!incorrect optimization parameter definition"
#endif
.endmacro
;--
#if	CodeOptimization == compact
uBUS_RELEASE_SUB:
	clr	TMP			;все линии ШД - направление "на ввод"
	out	uBUS_DATA_PortDIR,TMP
	;
	//Настроим данные для линии ALE=0; DLE=0; R/W=1 (состояние шины "RELEASE")
	cbi	uBUS_ALE_PortOUT,uBUS_ALE_line
	cbi	uBUS_DLE_PortOUT,uBUS_DLE_line
	sbi	uBUS_RW_PortOUT,uBUS_RW_line
	;
	ret
#endif
;------------------------------------------------------------------------------
;стартовая процедура настройки аппаратного окружения для работы с шиной uBUS
.macro	uBUS_Config
	call	uBUS_Config_SUB
.endmacro
;--
uBUS_Config_SUB:0
	clr	TMP			;зададим нулевой байт для вывода
	sts	S_uBUS_DATA,TMP
	clr	TMP2			
Clear_uBUS_OUTports:			;переберём все возможные порты вывода и выкинем на них нули  (по времени займёт меньше 400uS)
	call	uBUS_OUT_SUB		;выводим в цикле значение ячейки "S_uBUS_DATA" в номер порта, определяемой переменной цикла
	inc	TMP2			;
	brne	Clear_uBUS_OUTports	;крутим цикл вывода 256 раз
	// по окончании сформированы все сигналы для освобождения шины (ALE=0, DLE=0, R/W=1, ШД на ввод)
	;
	ret

;------------------------------------------------------------------------------

;Установка адреса IO регистра на шине
;Синтаксис:	Set_uBUS_IO_Address
;
;используемые регистры:
;  TMP2 - адрес IO-порта шины
.macro	Set_uBUS_IO_Address_fromTMP2
#if	CodeOptimization == fast
; - установка адреса порта
;	- запрещаем строб данных DLE=0
;	- переключение ШД на вывод и выводим на неё номера порта
;	- формируем строб записи адреса - короткий импульс ALE
;	  (на этот момент ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
	;
	cbi	uBUS_DLE_PortOUT,uBUS_DLE_line	;пока запрещаем вывод адреса порта с регистра адреса
	ser	TMP			;Переключение ШД на запись
	out	uBUS_DATA_PortDIR,TMP
	out	uBUS_DATA_PortOUT,TMP2	;Выводим на шину адрес I/O-регистра
	;--
	sbi	uBUS_ALE_PortOUT,uBUS_ALE_line	;Сформируем короткий импульс ALE
	cbi	uBUS_ALE_PortOUT,uBUS_ALE_line
	;
	// (ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
#elif	CodeOptimization == compact
	rcall	Set_uBUS_IO_Address_SUB
#else
	#error "!incorrect optimization parameter definition"
#endif
.endmacro
;--
#if	CodeOptimization == compact
Set_uBUS_IO_Address_SUB:
; - установка адреса порта
;	- запрещаем строб данных DLE=0
;	- переключение ШД на вывод и выводим на неё номера порта
;	- формируем строб записи адреса - короткий импульс ALE
;	  (на этот момент ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
	;
	cbi	uBUS_DLE_PortOUT,uBUS_DLE_line	;пока запрещаем вывод адреса порта с регистра адреса
	ser	TMP			;Переключение ШД на запись
	out	uBUS_DATA_PortDIR,TMP
	out	uBUS_DATA_PortOUT,TMP2	;Выводим на шину адрес I/O-регистра
	;--
	sbi	uBUS_ALE_PortOUT,uBUS_ALE_line	;Сформируем короткий импульс ALE
	cbi	uBUS_ALE_PortOUT,uBUS_ALE_line
	;
	// (ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
	ret
#endif
;------------------------------------------------------------------------------
;uBUS_IN			;Ввод информации с шины (In-порта) в её "регистр данных" (ячейку памяти "S_uBUS_DATA")
;Синтаксис:
;	uBUS_IN		uBUS_PortNum
;  где uBUS_IN - номер порта "IN" шины uBUS
;  считанные данные помещаются в ячейку памяти "S_uBUS_DATA"
.macro	uBUS_IN
	ldi	TMP2,@0
	call	uBUS_IN_SUB
.endmacro
;--
uBUS_IN_SUB:
;процедура чтения из порта:
;~~~~~~~~~~~~~~~~~~~~~~~~
; - настраиваемся на запись в шину (сигнал R/W=0)
; - установка адреса порта
;	- запрещаем строб данных DLE=0
;	- переключение ШД на вывод и выводим на неё номера порта
;	- формируем строб записи адреса - короткий импульс ALE
;	  (на этот момент ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
; - переключаем ШД на чтение
; - установим сигнал R/W в "1"
; - стробируем данные считываемые во входные регистры (эту функцию выполняет сигнал DLE)
; - считываем данные с нужного регистра, который на этот момент подсоединён к ШД
; - освобождаем шину, установив DLE=0, т.е. переводим в состояние "RELEASE" (IDLE)
;   (т.к. на текущей момент DLE="0", ALE = "0", R/W="1" и ЩД настроена на ввод данных)
;
	Set_uBUS_IO_Address_fromTMP2	;Установка адреса порта на шине
					;После этого сигналы ALE=0, DLE=0
					;направление ШД - "вывод", R/W не меняется
	clr	TMP
	out	uBUS_DATA_PortDIR,TMP	;Переключение ШД на чтение
	;
// установим сигнал R/W в "1"
//	(нормальная ситуация у нас почти постоянная "1" на линии R/W.
//	  "0" там только во время вывода новых данных в порт шины (OUT-регистры))
	sbi	uBUS_RW_PortOUT,uBUS_RW_line	;формируем сигнал чтения (R)
	;
// установим сигнал DLE в "1"
//	(после этого данные защёлкнутся во всех входных IN-регистрах,
//	  но к ШД будет подсоединён только с необходимым адресом)
	sbi	uBUS_DLE_PortOUT,uBUS_DLE_line
	;
	nop				;нужен хотя бы один "nop", чтобы данные на шине успели стабилизироваться
	nop
	;
	in	TMP,uBUS_DATA_PortIN	;Считаем данные с ШД (нужного IN-регистра шины)
	sts	S_uBUS_DATA,TMP		;Сохраним в буфере
	// Освобождаем шину (ALE=0, DLE=0, R/W=1, направление ЩД уже "на ввод")
	cbi	uBUS_DLE_PortOUT,uBUS_DLE_line ;а остальные (ALE=0; R/W=1) уже в норме
	;
	ret
;------------------------------------------------------------------------------
;uBUS_OUT		;Вывод информации с "регистра данных" (ячейки памяти "S_uBUS_DATA") на шину uBUS (Out-порт)
;Синтаксис:
;	uBUS_OUT	uBUS_PortNum
;  где uBUS_OUT - номер порта "IN" шины uBUS
;  данные для вывода на шину берутся из ячейки памяти "S_uBUS_DATA"
.macro	uBUS_OUT
	ldi	TMP2,@0
	call	uBUS_OUT_SUB
.endmacro
;--
uBUS_OUT_SUB:
;процедура записи в порт:
;~~~~~~~~~~~~~~~~~~~~~~~~
; - настраиваемся на запись в шину (сигнал R/W=0)
; - установка адреса порта
;	- запрещаем строб данных DLE=0
;	- переключение ШД на вывод и выводим на неё номера порта
;	- формируем строб записи адреса - короткий импульс ALE
;	  (на этот момент ALE=0, DLE=0, но направление ШД сейчас - "на вывод")
; - вывод байта данных на ЩД
; - стробируем данные для записи на шину (эту функцию выполняет сигнал DLE)
; - освобождаем шину, т.е. переводим в состояние "RELEASE" (DLE="0", ALE = "0", R/W="1")
;
	cbi	uBUS_RW_PortOUT,uBUS_RW_line	;будем выводить данные в шину
	Set_uBUS_IO_Address_fromTMP2	;Установка адреса порта на шине
					;и ШД после установки адреса уже в состоянии выхода (записи)
	;------------------
	;
	lds	TMP,S_uBUS_DATA		;Возьмём в буфере данные, которые нужно вывести
	out	uBUS_DATA_PortOUT,TMP	;выведем их на шину
	;
// установим разрешение строба записи (эту функцию выполняет сигнал DLE)
//	(по этому импульсу разрешится работа дешифратора адреса выходных портов,
//	  и как паразитный эффект - данные входных линий защёлкнутся в IN-регистрах)
	sbi	uBUS_DLE_PortOUT,uBUS_DLE_line
	cbi	uBUS_DLE_PortOUT,uBUS_DLE_line	;ALE=0 к этому времени, а теперь и DLE=0
	;
	// ALE=0; DLE=0; установим теперь ШД на ввод
	clr	TMP
	out	uBUS_DATA_PortDIR,TMP	;Переключение ШД на чтение
	// теперь переключим сигнал R/W=1
	sbi	uBUS_RW_PortOUT,uBUS_RW_line	;R=1
	// теперь шина в состоянии RELEASE (IDLE)
	// (ALE=0, DLE=0, R/W=1, ШД - ввод)
	;
	ret








--------

...делать нужно так, как нужно. А как ненужно - делать не нужно (С) Винни-Пух :)