Главная » Микроконтроллеры
Призовой фонд
на май 2017 г.
1. Тестер компонентов MG328
Паяльник
2. Осциллограф DSO138
Паяльник
3. Регулируемый паяльник 60 Вт
Паяльник
4. 100 руб.
От пользователей

Распределение памяти между задачами

Существует и еще две важных причины, по которым ОСРВ, приведенная в листинге предыдущей главы, не сможет найти широкого применения. Во-первых, разные задачи могут использовать одни и те же регистры. А при переключении задач РОНы, как и SREG, нужно где-то сохранить. В принципе, этот вопрос можно решить: отвести для каждой задачи свою область памяти и переписывать туда их содержимое. Но такой обработчик потеряет “гибкость”, будет занимать много памяти и медленно выполнятся. Второй, и уже не разрешимой проблемой, окажется то, что в ходе выполнения задачи будет невозможно вызывать подпрограммы. Это легко можно увидеть на следующем примере. Допустим, в задаче 1 встретилась инструкция rcall, после чего адрес возврата из подпрограммы был сохранен в стеке. Через некоторое время возникает прерывание, в работу вмешивается ОСРВ и запускает задачу 2. Если теперь в задаче 2 встреться команда ret, то произойдет переход по последнему адресу, записанному в стеке, т.е. переход в некоторую точку задачи 1. Из всего вышесказанного можно сделать вывод, что для полноценного функционирования ОСРВ, помимо прочих ресурсов, каждая задача должна иметь еще и свой собственный стек для размещения своего контекста (регистров, адресов возврата и т.д.).

ОСРВ, приведенная в листинге ниже, подобно примеру в листинге предыдущей главы также управляет работой двух задач, но с некоторыми изменениями. В ней цикл задержки времени вынесен в отдельную подпрограмму pause, которая теперь может быть доступна для совместного использования. Кроме этого все переменные системы расположены в SRAM. Каждая задача имеет свое адресное пространство памяти данных размером MAMSPACE = 64 б. Задача 1 занимает диапазон адресов 0x060-0x09F, начиная с метки mem1; задача 2 - 0x0A0-0x09F-0x0DF, начиная с mem2.

Состояние памяти двух задач в ОСРВ
Рис.1 Состояние памяти двух задач в ОСРВ
а - во время выполнения задачи 1
б - при переключении контекстов задач
в - во время выполнения задачи 2

Состоянием памяти сразу после инициализации программы показано на рис.1а. В данный момент времени активна задача 1. Дно стека совпадает с самым верхним адресом ее адресного пространства(SP = 0x09F). На рис.1б показано, какие действия производит ОС для переключения контекста задачи 1 на контекст задачи 2, в случае если прерывание произошло, когда PC = 0x0280 и SP = 0x009D, т.е. в ходе выполнения подпрограммы задержки времени. Самое первое, что сделает ОС - это сохранит в стеке текущей задачи все РОНы и SREG. Указатель стека при этом переместится до уровня SP = 0x007A. На самом нижнем уровне будет находиться адрес возврата 0x0106, сохраненный при вызове подпрограммы pause. Следующие 2 байта – адрес возврата 0x0281 после выхода из прерывания. Далее 32 РОНа и SREG. Итого общий размер стека составит 37 б. На следующем шаге происходит сохранение SP задачи 1 в ячейках sp1h:sp1l и загрузка в SP из sp2h:sp2l нового значения указателя стека задачи 2. В ходе первого прерывания это значение после инициализации 0x0281. Теперь из стека восстанавливается контекст второй задачи (32 РОН и SREG) и после команды reti программа продолжает выполняться с метки task2 (PC = 0x0200), что является начальным адресом возврата в задачу 2(рис.2в). После того, как истечет время отведенное задаче 2, ОСРВ таким-же образом передаст управление задаче 1 (сохранит контекст задачи 1, сохранит SP задачи 1, загрузит SP задачи 2, восстановит контекст задачи 2) и т.д.

 .include "m8def.inc"
  
 .equ DELAY    = 100 ;задержка времени
 .equ MEMSPACE = 64  ;размер адресного пространства задачи

 .def temp     = R16 ;регистр для промежуточных операций
 .def mask     = R17 ;временный регистр
 .def cnt      = R18 ;счетчик циклов
 .def templ    = R19 ;регистры для промежуточных операций при
 .def temph    = R20;сохранении и восстановлении адреса возврата

      .dseg
	  .org  0x060 
   mem1:   .byte  MEMSPACE  ;адресное пространство задачи 1 
   mem2:   .byte  MEMSPACE  ;адресное пространство задачи 2  
   sp1h:   .byte  1 ;старший байт указателя стека задачи 1
   sp1l:   .byte  1 ;младший байт указателя стека задачи 1
   sp2h:   .byte  1 ;старший байт указателя стека задачи 2
   sp2l:   .byte  1 ;младший байт указателя стека задачи 1
   tsknum: .byte  1 ;ячейка хранения номера текущей задачи

      .cseg
      .org  0
     rjmp  initial 

      .org  0x0009
     rjmp  service_T0OVER

      .org  0x0020
initial: 
    clr   temp             ;чистка SRAM перед началом работы
	ldi   ZH,high(SRAM_START)
    ldi   ZL,low(SRAM_START)
	ldi   YH,high(SRAM_SIZE)
	ldi   YL,low(SRAM_SIZE)
mcl: st    Z+,temp
	sbiw  YH:YL,1
	brne  mcl
    sbi   DDRB,DDB0     ;установка линии 0 порта B на вывод 
    sbi   DDRB,DDB1     ;установка линии 1 порта B на вывод
    ldi   temp,(1 << CS02)|(1 << CS00)  ;включение таймера 0 с 
    out   TCCR0,temp                ;предделителем  F/1024
    ldi   temp,1 << TOIE0  ;разрешение прерывания по переполнению 
    out   TIMSK,temp     ;таймера 0 (период T = F/1024/256) 
     
    ldi   temp,low(task2)         ;загрузка начального адреса 
	sts   mem2+MEMSPACE-1,temp    ;возврата task2 = 0x0200 на 
	ldi   temp,high(task2)        ;дно стека 0x0DF задачи 2
	sts   mem2+MEMSPACE-2,temp
	ldi   temp,high(mem2+MEMSPACE-36) ;инициализация стека
	sts   sp2h,temp                   ;задачи 2 на SP = 0x0BD
	ldi   temp,low(mem2+MEMSPACE-35)
	sts   sp2l,temp
	ldi   temp,high(mem1+MEMSPACE-1)  ;инициализация стека	
    out   SPH,temp                    ;задачи 1 на SP = 0x09F 
	ldi   temp,low(mem1+MEMSPACE-1)
	out   SPL,temp
    ldi   temp,1     ;заносим номер текущей задачи
	sts   tsknum,temp
	sei              ;глобальное разрешение прерываний
	rjmp  task1      ;переходим к выполнению задачи 1

       .org  0x0100 
task1:                  ;    PC    SP          
     in    temp,PORTB  
     ldi   mask,1 << PB0
     eor   mask,temp   
     out   PORTB,mask
     ldi   cnt,DELAY     
     rcall pause         
     rjmp  task1        

       .org  0x0200
task2:
     in    temp,PORTB  ;0x0200 0x00DF <- Выход из прерывания 1
     ldi   mask,1 << PB1 
     eor   mask,temp
     out   PORTB,mask
     ldi   cnt,DELAY/2 
     rcall pause         
     rjmp  task2 
 
       .org  0x0280
pause:
    dec   cnt         ;0x0280 0x009D <- Прерывание 1
	brne  pause       
	ret
       
       .org  0x0300
service_T0OVER:
    push  R0         ;сохранение контекста текущей задачи
	push  R1
	push  R2
	push  R3
	push  R4 
    push  R5   
    .
	push  R26
	push  R27
	push  R28
	push  R29
	push  R30
	push  R31
    in    temp,SREG
	push  temp
    in    temph,SPH
	in    templ,SPL
	lds   temp,tsknum
	cpi   temp,1
	brne  sr1
	sts   sp1h,temph   ;если прерывание возникло при выполнении   
	sts   sp1l,templ   ;задачи 1, то сохраняем указатель стека 
	lds   temph,sp2h   ;задачи 1 в sp1h:sp1l и заносим во 
	lds   templ,sp2l   ;временные регистры temph:templ указатель 
	ldi   temp,2       ;стека задачи 2
	rjmp  sr2
sr1: sts   sp2h,temph   ;если прерывание возникло при выполнении   
	sts   sp2l,templ   ;задачи 2, то сохраняем указатель стека
	lds   temph,sp1h   ;задачи 2 в sp2h:sp2l и заносим во 
	lds   templ,sp1l   ;временные регистры temph:templ указатель
	ldi   temp,1       ;стека задачи 1
sr2: sts   tsknum,temp
    out   SPH,temph    ;загрузка в стек нового значения                 
	out   SPL,templ    ;из временных регистров temph:templ    
	pop   temp
	out   SREG,temp
	pop   R31
	pop   R30
	pop   R29
	pop   R28
	pop   R27
	pop   R26
    .
	pop   R5
	pop   R4
	pop   R3
	pop   R2
	pop   R1
	pop   R0          ;восстановление контекста следующей задачи
	reti

Выше показан наиболее общий случай, когда контекст каждой задачи сохраняется целиком. В нашем примере, конечно, нет необходимости заботится о сохранении всех 32 регистров. Для работы каждой задачи требуется только 3. Кроме того размер адресного пространства у каждой из задач тоже избыточен поскольку максимальная глубина стека не превысит 8 б.

Перейти к следующей части:

Теги:

Котов Игорь Юрьевич Опубликована: 2012 г. 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (0) | Я собрал (0) | Подписаться

Статью еще никто не комментировал. Вы можете стать первым.
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическая мощность?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

AVR-программатор USB ASP
AVR-программатор USB ASP
Квадрокоптер Syma X11 Набор для сборки - УНЧ 2х60 Вт на TDA7294
вверх