MSP430 - учебный курс. Часть 3 - ядро, память и режимы адресации.

Итак, приступим к третьему уроку.

План на сегодня таков:
1. Ядро — краткий обзор.
2. Словный и байтный формат команд.
3. Структура памяти.
4. Режимы адресации.

Начнем, пожалуй.

Кстати, пришел заказанный MSP430F247 — ура! Ну а пока я к нему привыкаю, рассмотрим мой любимый MSP430F149.

Это старшая модель в семействе MSP430x1xx — лапы и периферия по максимуму.
Кратенько характеристики:
— Тактовая частота — до 8 МГц.
— Три источника тактирования — один внутренний и два внешних.
— 64 ноги (в корпусе QFP c шагом 0.5 мм).
— ОЗУ — 2Кб.
— ПЗУ (типа FLASH) — 60 Кб.
— ЭСППЗУ (EEPROM) — 256 б.
— 6 групп портов ввода/вывода (43 порта) — пять по 8 и один 3 линии.
— 16-ти битные таймеры (2 штуки, но очень хитрые).
— 12 бит АЦП, компаратор.
— SPI, USART.
— JTAG.
— Аппаратный умножитель (нет специальной команды умножения).

Вот внутренняя структура семейства:


Внутренний источник тактирования DCO (Digital Controlled Oscillator) построен на RC-цепочке и имеет частоту около 750 кГц (сильно зависит от температуры).
Внешние источники:
LFXT1 — работает в двух режимах: высокочастотном (450 кГц… 8 МГц) и низкочастотном (оптимизирован под часовой кварц 32768 Гц).
XT2 — высокочастотный — 450 кГц… 8 МГц.
Выбор источника тактирования осуществляется программно. При этом, по умолчанию запускается на встроенном. Если мы пытаемся подключить внешний источник и нам это не удалось, контроллер вернётся к работе на встроенный и не зависнет.

1. Ядро

Основное о ядре:
— 16-ти битная шина адреса (адресует до 64 Кб памяти).
— 16-ти битная шина данных.
— Ортогональная архитектура (любой режим адресации пригоден для команды, правда есть заморочки для второго операнда).
— 16 регистров (4 РСН и 12 РОН) — все могут быть указателями.
— Прямой обмен «память -> память».
— 51 команда: 27 команд ядра (аппаратных) и 24 эмулированных (псевдонимы).
— Байтный и словный формат команд.
— Генератор констант, сокращающий код в определённых случаях.

Регистры кратко.
R0 — PC (program counter) — счётчик команд.
R1 — SP (stack pointer) — указатель стека. Не забудьте инициализировать!
R2 — SR (status register) — регистр состояния и управления. Содержит основные флаги состояния, а также флаги управления режимами работы.
R3 — CG (constant generator) — генератор констант.
R4..R15 — просто регистры общего назначения.

Эмулированные команды — это фикция компилятора. В конечном итоге они будут заменены на какую-либо команду с определённой комбинацией операндов. К примеру «NOP» заменяется на «MOV #0, R3».
О генераторе констант поговорим подробнее позже.

2. Словный и байтный формат команд.

Все команды, кроме переходов, поддерживают как побайтное обращение к операндам, так и пословное (2 байта).
При написании команды ставится признак типа обращения.
Например:

mov        R4, R5 ; пословная форма, по умолчанию
mov.w      R4, R5 ; пословная форма, с явным указанием
mov.b      R4, R5 ; побайтная форма, только с явным указанием

Здесь мы копируем содержимое регистра R4 в R5.
В последнем случае, в младший байт R5 будет помещен младший байт R4, а в старший байт R5 будет помещен 0.
Обращение к байтам — как по чётным, так и по нечётным адресам. К словам — только по чётным.

3. Структура памяти.

Распределение памяти в контроллере интересное. Т.к. Архитектура Фон-Неймана, то всё находиться в едином адресном пространстве памяти (если кто знаком с x86, тот знает, что там есть ещё одна адресная ось — регистры ввода/вывода, в MSP430 этого нет). Полюбуйтесь:

Внимание! На картинке показано не всё (без BSL и ЭСППЗУ), см. описание ниже.

Диапазон адресов — 0000h..000Fh.
В самом низу — регистры специального назначения (не путать с регистрами в ядре!). Их состав зависит от конкретной модели микроконтроллера и предназначены они для работы с некоторыми функциями периферии. Обращение — побайтное.

Диапазон адресов — 0010h..00FFh.
Здесь находятся восьмиразрядные регистры модулей периферии. Обращение — побайтное.

Диапазон адресов — 0100h..01FFh.
Здесь находятся шестнадцатиразрядные регистры модулей периферии. Обращение — побайтное и пословное.

Первые три области памяти в IAR отображаются как тип SFR вместе — будьте внимательны.

Диапазон адресов — 0200h..09FFh.
ОЗУ. Начальный адрес фиксирован (0200h). Конечный адрес зависит от объёма памяти в микроконтроллере. Я указал для 2Кб. Обращение — побайтное и пословное.

Диапазон адресов — 0C00h..0FFFh.
Область BSL (Bootstrap Loader). Предустановленный загрузчик, работает через USART. Пока трогать не будем.

Диапазон адресов — 1000h..10FFh.
ЭСППЗУ (EEPROM). Тут всё понятно.

Диапазон адресов — 1100h..FFFFh.
ПЗУ. Конечный адрес фиксирован (FFFFh), начальный зависит от модели микроконтроллера (по объёму ПЗУ). Я привёл для 60 Кб.
Старшие 16 слов ПЗУ отведены под вектора прерывания. Самый последний всегда RESET, остальное зависит от модели.
Обращение — побайтное и пословное.

Размещение слова в памяти — младшая часть по меньшему адресу, старшая часть по большему адресу (little-endian, совпадает с принятым в архитектуре x86).

4. Режимы адресации.
Вот тут самое интересное место.
У MSP430 семь режимов адресации (в реальности меньше, некоторые являются модификациями).

1. Регистровый.
Пересылка из/в регистр. Например:

        mov     R4,     R5        ; поместить содержимое R4 в R5

Применим к источнику и приёмнику.

2. Индексный.
Пересылка с применением регистра в качестве указателя и смещением.

        mov     R4,     2(R5)     ; поместить содержимое R4 в ячейку памяти с адресом [2+R5]
или
        mov     0(R4),  4(R5)     ; поместить содержимое ячейки памяти с адресом [0+R4] в ячейку памяти с адресом [4+R5]

Смещение(я) идет после кода команды, посему может быть 0..65535.
Применим к источнику и приёмнику.

3. Символьный режим.
Пересылка с исчислением смещения от PC.

        mov     R4, Dest          ; поместить содержимое R4 в ячейку памяти с адресом Dest
или
        mov     Src, R4           ; поместить содержимое ячейки памяти с адресом Src в R4

Зверюка похитрее, но на самом деле оказывается модификацией индексного режима. Т.е. данная команда эквивалентна

        mov     R4, X(PC)
или
        mov     Y(PC), R4

Где Х = Dest-PC, т.е. разнице содержимого программного счетчика и адреса Dest. Аналогично, для второй Y = Src — PC.
Но! Тут кроется большущий подводный камень. Нельзя указывать в операнде значение адреса цифрами, только символьное имя метки. Вернее не совсем нельзя, просто иначе компилятор творит чудеса и вы не получите ожидаемый результат.

	mov	Val1, R7		; можно
	mov	0x200, R7		; нельзя!
	mov	R6, Val1		; можно
	mov	R6, 0x200		; нельзя!

Val1 у меня расположен по адресу 200h.
Данный режим, чаще всего, используется для создания перемещаемого кода, исполняемого в ОЗУ.
Применим к источнику и приёмнику.

4. Абсолютный режим.
Пересылка по адресу, указываемому в коде команды. Адрес должен быть известен на момент компиляции.

        mov     R4, &Dest          ; поместить содержимое R4 в ячейку памяти с адресом Dest
или
        mov     &Src, R4           ; поместить содержимое ячейки памяти с адресом Src в R4

Вроде бы операции такие же, как и в примере к предыдущему режиму, но адрес не вычисляется, а берется непосредственный.
Поэтому здесь можно указывать адрес цифрами.

        mov     R4, &0x200         ; поместить содержимое R4 в ячейку памяти с адресом 200h
или
        mov     &0x200, R4         ; поместить содержимое ячейки памяти с адресом 200h в R4

Применим к источнику и приёмнику.

5. Косвенный регистровый режим.
Пересылка по адресу, указанному в регистре (здесь без смещения).

        mov     @R4, R5            ; поместить содержимое ячейки с адресом [R4] в R5

Применим только к источнику.

6. Косвенный регистровый режим с автоинкрементом.
Пересылка по адресу, указанному в регистре (здесь без смещения).

        mov     @R4+, R5            ; поместить содержимое ячейки с адресом [R4] в R5, после чего увеличить R4 на 2

Применим только к источнику.

7. Непосредственный режим.
Пересылка значения.

        mov     #0x200, R5            ; поместить число 200h в R5
или
        mov     #Val1, R5             ; поместить значение адреса Val1 в R5
или
        call    #Sub1                 ; вызвать подпрограмму по адресу [Sub1]

Применим только к источнику.
Относительно последней строчки примера — так нужно делать для call, но не для jmp.

Ну всё, я спать, а на следующем уроке рассмотрим генератор констант и систему тактирования.
А для затравки пример по режимам адресации.

#include "msp430.h"                     ; #define controlled include file

        NAME    main                    ; module name

        PUBLIC  main                    ; make the main label vissible
                                        ; outside this module
        ORG     0FFFEh
        DC16    init                    ; set reset vector to 'init' label

        RSEG    CSTACK                  ; pre-declaration of segment
        RSEG    CODE                    ; place program in 'CODE' segment

init:   MOV     #SFE(CSTACK), SP        ; set up stack

main:   NOP                             ; main program
        MOV.W   #WDTPW+WDTHOLD,&WDTCTL  ; Stop watchdog timer
        
	nop
	
	mov	PC, R7
	
	mov     #0x200, R4		; поместить число 200h в R4

	; Регистровый
        mov     R4, R5			; поместить содержимое R4 в R5

	; Индексный
        mov     R4, 2(R5)		; поместить содержимое R4 в ячейку памяти с адресом [2+R5]
	mov	0(R4), 4(R5)		; поместить содержимое ячейки памяти с адресом [0+R4] в ячейку памяти с адресом [4+R5]
	
	; Символьный
	mov	Val1, R6		; поместить содержимое ячейки Val1 в R6
	mov	0x200, R7		; а так нельзя !!!
	mov	Const1, R6		; поместить содержимое ячейки Const1 в R6
	mov	Const2, R7		; поместить содержимое ячейки Const2 в R7
	mov	R6, Val1		; поместить содержимое R6 в ячейку Val1
	mov	R7, 0x200		; а так нельзя !!!

	; Абсолютный
	mov	&Val1, R7		; поместить содержимое ячейки Val1 в R7
	mov	&0x200, R6		; поместить содержимое ячейки с адресом  200h в R6
	mov	&Const1, R6		; поместить содержимое ячейки Const1 в R6
	mov	&Const2, R7		; поместить содержимое ячейки Const2 в R7
	mov	R7, &Val1		; поместить содержимое R7 в ячейку Val1
	mov	R6, &0x200		; поместить содержимое R6 в ячейку с адресом  200h
	
	; Косвенный регистровый
	mov	@R4, R5			; поместить содержимое ячейки с адресом [R4] в R5
        
	; Косвенный регистровый с автоинкрементом
	mov	@R4+, R5		; поместить содержимое ячейки с адресом [R4] в R5, после чего увеличить R4 на 2
	mov	@R4+, R5		; поместить содержимое ячейки с адресом [R4] в R5, после чего увеличить R4 на 2
	mov	@R4+, R5		; поместить содержимое ячейки с адресом [R4] в R5, после чего увеличить R4 на 2
	
	; Непосредственный
	mov	#0x200, R4		; поместить число 200h в R4
	mov	#Val1, R5		; поместить значение адреса Val1 в R5
	call	#Sub1			; вызвать подпрограмму по адресу [Sub1]

	JMP	$			; jump to current location '$'
					; (endless loop)
					
Sub1:
	nop				; 
	ret				; 

;	RAM definition
	RSEG	DATA16_N
Val1:	
	DS16	1

;	ROM definition
	RSEG	DATA16_C
Const1:
	DC16	0x5AA5
Const2:
	DC16	0x0FF0

					
        END


P.S.

Некоторые замечания по материалу (так сказать вдогонку).

Замечание 1. По режимам адресации.
Т.к. регистры ядра не имеют физического адреса, выражаемого числом, то к ним неприменимы следующие режимы адресации:
— символьный;
— абсолютный;
— непосредственный.

Замечание2. По байтному и словному доступу.
В словном режиме недопустимо обращение по нечётным адресам памяти!
При обмене «регистр -> память»:
— при словном режиме младшая часть регистра помещается по меньшему (чётному) адресу, старшая по следующему (+1).
— при байтном режиме по адресу обращения помещается младшая часть, старшая игнорируется.

При обмене «память -> регистр»:
— при словном режиме в младшую часть регистра помещается значение из меньшего (чётного) адреса, в старшую из следующего (+1).
— при байтном режиме в младшую часть регистра помещается значение из ячейки по адресу обращения, в старшую заносится 0.

Замечание 3. Регистр PC (aka R0).
Инкремент счетчика команд (только на число, кратное 2!) происходит в момент предшествующий дешифрации команды, после выборки. Это значит, что на момент исполнения команды, счётчик команд указывает на следующую команду. Т.е. код:

mov     PC, R4

даст нам в R4 указатель не на эту команду, а на следующую (в данном случае +2).

  • 0
  • 16 марта 2011, 05:16
  • SerjT

Комментарии (16)

RSS свернуть / развернуть
Подходим, граждане, пинаем ногами.
Что дать на следующие уроки в первую очередь?
0
Я присоеденяюсь к AKL: желательно начать с более новых value line процессоров — потому что у многих для опытов есть например тот же LaunchPad который стоит копейки (~5$). Исходя из практики — будут чаще использовать именно маленкие процессоры с в маленьком корпусе. Я вот например получиз задание сделать логер с питанием от батарейки 1,5в и так как ПИК я не люблю а АВР немогу заставить уже жрать меньше — купил себе именно LaunchPad и к нему несколько разных процссоров дополнительно. То что асемблер — я думаю нестрашно… Но будет лучше если будет описан способ использования вставок АСМ в С. Потому что из опыта известно что пишется в основном на С и потом оптимализируется вставками :)
0
Хороший процессор — F149. Я когда-то на практике по нему методичку писал. Самая главная беда тогда была — перевод терминов с русского и английского на украинский)
0
:-)
Так «ланцюгi» або «мережи»? Споры не утихают до сих пор. Говорят, в некоторых ВУЗах доходило до драк между писателями книг и статей и рецензентами…
0
Здравствуйте. Приветствую появление материалов по MSP430. Хотелось, что бы в последующем были отражены или акцентированы некоторые моменты
-появление в серии новых подсемейств не заставляет дрожать по поводу снятия с производства старых.
Они по прежнему остаются активными, т.к. это политика TI
-порты ввода-вывода имеют 8-разрядную шину и обращение к ним осуществляется командами MOV.B
-контроллеры не имеют каких бы то ни было битов конфигурации. Все отдано на откуп программисту
-система команд взята в основном от PDP11 и имеет всего 27 базовых команд, включая команды работы в десятичной арифметике. За счет эмуляции ассемблер поддерживает 51 команду
-развитая система режимов пониженного потребления и очень быстрая смена частоты тактирования
-из практики применения. MSP430 весьма живучи.
-хотелось бы увидеть связь с внешней средой. Хоть светиком помыргать. Сначала программно, потом таймером и т.д.
-начальная ориентация на старший камень в подсемействе, боюсь оттолкнет потенциальных юзеров. Здесь и вопросы цены и аппаратной поддержки. Думаю, не каждый рискнет начать с 64-лапой F147(148,149) в QFP или QFN корпусах, а вот F1121 в SOIC более реально.
-очень важный вопрос это программирование
0
  • avatar
  • akl
  • 16 марта 2011, 10:50
Постепенно всё это будет.
Сначала закончу основное по ядру, потом перейдём к портам, таймерам и прочей периферии.
Просто я даю материал так, чтобы народ мог начать не имея аппаратуры. Изучить команды, можно в программной эмуляции в IAR.
Насчёт новых серий — я специально приобрёл 247-й, чтобы потом перейти к отладке в PROTEUS, т.к. и кристалл достаточно новый, и отличий от соток немного, и в библиотеках PROTEUS он есть.
А насчет маленьких — так там отличия будут в количестве периферии и ног, остальное одинаково. Просто у меня уже есть отладочный комплект с панелькой под 64 ноги, а приобретать что-то новое сложновато. Если у кого-то имеется бесхозная плата под FET140 (LPT-шный) для маленьких кристаллов — сообщите. Рассмотрю возможность приобретения (только я аж в Севастополе).
Программирование тема ещё та. Если есть LPT, то несложно сообразить простой программатор по схеме от TI. Она в свободном доступе, описана в документации на FET. Но для USB — проблема. Если для AVR полно схем и прошивок, то для MSP практически ничего нет.
Так что жду ещё пожеланий. Завтра постараюсь выкатить четвертый урок.
0
Вы хоть напишите — нормально изложен материал или что-то изменить, рассказать подробнее. А то я без отзывов не могу понять — нужно это или нет.
Пожелания приветствуются: что хотелось бы увидеть поскорее. Я планирую ещё урок по ядру, а потом переходим к портам. Затем таймеры.
Не могу сказать, что я профессионально занимаюсь этим контроллером — только второй семестр веду лабораторные занятия по нему. В инженерной деятельности не применяю, там у меня царство PIC. Поэтому мог что-то упустить. В общем — пишите чаше и я буду в курсе того, что необходимо.
0
Ну например у меня есть вот этот девайс LaunchPad и стоит он и с УСБ отладкой 4,3 долара!!!
0
Ты эти цены украинским поставщикам покажи…
И ещё найди того, кто их к нам привезёт.
Думаю долларов 15-20 за штуку здесь посчитают оскорблением.

Да и ограничена серия G в возможностях слегонца…
0
То что ограничена — это ясно… Но цена, розмеры чипа и потребление подходя как нельзя лучше! Мне надо думать в фирме не только о том как сделать но и за сколько сделать :) А то что вас там тупо дурят — это ваши проблемы — я заказывал прямо от TI и всё пришло за ту цену как написали. Возможно играет роль и то что я живу в европе :)
0
Да Вы, батенька, хорошо живёте…
Вы с нашими акулами бизнеса не сталкивались. И это не совсем наши проблемы. И с оплатой «в туда» геморрой.

А по поводу экономической эффективности — все мы об этом думаем. Просто у меня есть в наличии определённый инструментарий и тратить деньги на новый пока мне не выгодно — деньги зарабатываю на другом :-)

По серии G статьи пишет _YS_ и нет смысла его дублировать.
0
Стиль Мне нравится. Вроде так лаконично, четко и по делу. А вот вопросы будут потом, когда народ ковыряющий сейчас MSP нагуглит эти статьи. Просто процы эти не сильно распространены (в том числе потому что мало инфы толковой и понятной) и количество пользователей сайта кто способен задать вопросы пока мало.
0
Спасибо за статью, отличное изложение. Несмотря на то, что я уже вроде как освоился с MSP430 по английским мануалам, все равно объяснение на русском, да еще и с комментариями профи, очень помогает проникнуться до конца.

>«Я присоеденяюсь к AKL: желательно начать с более новых value line процессоров — потому что у многих для опытов есть например тот же LaunchPad который стоит копейки (~5$).»

Там все то же самое — то же ядро, та же периферия. Разница только в ее количестве. Это я Вам как лаунчпадовод говорю.

>«Но будет лучше если будет описан способ использования вставок АСМ в С.»

Лично я использую функции, целиком написанные на ассемблере и оформленные в отдельный модуль. Если владеете языком вероятного противника, Вам поможет аппноут от TI на эту тему. Вкратце — первые два параметра передаются в регистрах [R13:]R12 и [R15:]R14 (регистры в квадратных скобках исользуются только если параметр больше 16 бит), остальное — в стеке начиная с последнего параметра. Результат возвращается в [R13:]R12.

Ассемблерный листинг имеет расширение .s43 и следующую структуру:

#include «специфичный_для_МК_заголовочник.h»

NAME имя_модуля

PUBLIC имя_функции1, имя_функции2,…

RSEG CODE

имя_функции1:

[код функции на ассемблере, ровно такой, как описано]
ret


END

В С пишем

extern [тип] имя_функции1([параметры]);

Все. Можно использовать. Как видно, никакой особой хитрости (в первом приближении).
0
  • avatar
  • _YS_
  • 16 марта 2011, 22:21
Перечитал еще раз, много думал.

Все же небольшой вопрос: я правильно понимаю, что режимы 0(reg) и @reg суть одно и то же с той лишь разницей, что первый применим исключительно к источнику и поддерживает автоинкремент?

Т.е.

mov 0(reg1),reg2

равносильно

mov @reg1,reg2

и можно писать

mov reg1,0(reg2)

но нельзя

mov reg1,@reg2

и нельзя

mov 0(reg1)+,reg2?
0
  • avatar
  • _YS_
  • 16 марта 2011, 22:37
Истину глаголешь…

По первому примеру — да, фактически действия равносильны, НО…
mov 0(reg1),reg2
порождает лишнее слово в коде (смещение после кода команды) и увеличивает на 1 такт исполнение команды (надо выбрать операнд из памяти). И опять НО! Компилятор не дурак, он просто подменит индексное обращение со смещением 0 на косвенное. Т.е., вместо "mov 0(reg1),reg2" он поставит "mov @reg1,reg2".

Второе
и можно писать

mov reg1,0(reg2)

но нельзя

mov reg1,@reg2
именно, т.к. косвенный режим для приёмника не поддерживается (кажется ограничение по длине команды, как и в других процах — просто бит не хватило)

Третье
и нельзя

mov 0(reg1)+,reg2
тоже нет, т.к. для индексного режима нет автоинкремента.
0
Спасибо, разобрался.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.