В предыдущей части урока мы подключили новый модуль, познакомились со стеком, а также научились обеспечивать видимость продпрограмм других модулей.
Аналогичным образом отключим PLL
1 2 3 4 5 6 7 8 9 10 11 12 |
BNE wait_cfgrsws ;Clear bit RCC_CR_PLLON in register RCC_CR LDR R2, =(PERIPH_BB_BASE + (RCC_CR - PERIPH_BASE) * 32 + RCC_CR_PLLON_N * 4) STR R0, [R2] LDR R2, =RCC_CR wait_pllrdy_res LDR R3,[R2] ; читаем регистр RCC_CR AND R3, R3, #RCC_CR_PLLRDY CMP R3, #0 BNE wait_pllrdy_res |
Так как очищали мы только один бит, логичнее было применить бит-бэндинг.
Выключим HSE и его детектор тактового сигнала, дождавшись затем отключения HSE
1 2 3 4 5 6 7 8 9 10 11 12 |
BNE wait_pllrdy_res ;Clear bits RCC_CR_HSEON and RCC_CR_CSSON in register RCC_CR LDR R3, [R2] BIC R3, R3, #(RCC_CR_HSEON + RCC_CR_CSSON) STR R3, [R2] wait_hserdy_res LDR R3,[R2] ; читаем регистр RCC_CR AND R3, R3, #RCC_CR_HSERDY CMP R3, #0 BNE wait_hserdy_res |
Сбросим бит, разрешающий использование внешнего генератора
1 2 3 4 5 |
BNE wait_hserdy_res ;Clear bit RCC_CR_HSEBYP in register RCC_CR LDR R2, =(PERIPH_BB_BASE + (RCC_CR - PERIPH_BASE) * 32 + RCC_CR_HSEBYP_N * 4) STR R0, [R2] |
Сбросим флаги всех прерываний от RCC
1 2 3 4 5 |
STR R0, [R2] ;Reset all CSR flags LDR R2, =(PERIPH_BB_BASE + (RCC_CSR - PERIPH_BASE) * 32 + RCC_CSR_RMVF_N * 4) STR R1, [R2] |
Вот и вся процедура деинициализации RCC. Думаю, что инициализацию мы напишем быстрее, так как мы теперь знакомы с многими командами и с тем, как и где их применять.
Вернёмся в main.s и, прежде чем вызывать инициализацию, поделаем ещё некоторые шаги.
Включим тактирование AFIO
1 2 3 4 5 |
MOV R1, #1 ;Alternate Function I/O clock enable LDR R2, =(PERIPH_BB_BASE + (RCC_APB2ENR - PERIPH_BASE) * 32 + RCC_APB2ENR_AFIOEN_N * 4) STR R1, [R2] |
Здесь нам нужна небольшая задержа. Применим вот такой финт
1 2 3 |
STR R1, [R2] ;Delay after clock enabling LDR R2, [R2] |
Мы просто считали значение, находящееся по адресу, находящемуся в R2 в сам регистр R2.
Настроим SWD
1 2 3 4 5 6 7 8 9 |
LDR R2, [R2] ;NOJTAG: JTAG-DP Disabled and SW-DP Enabled LDR R2, =AFIO_MAPR LDR R3, [R2] BIC R3, R3, #AFIO_MAPR_SWJ_CFG STR R3, [R2] ;Set bit AFIO_MAPR_SWJ_CFG_JTAGDISABLE in register AFIO_MAPR LDR R2, =(PERIPH_BB_BASE + (AFIO_MAPR - PERIPH_BASE) * 32 + AFIO_MAPR_SWJ_CFG_JTAGDISABLE_N * 4) STR R1, [R2] |
Вот теперь мы можем инициализировать наш RCC, для чего вернёмся в файл rcc.s и после окончания процедуры деинициализации RCC добавим заготовку для процедуры инициализации, в теле которой мы также занесём значения регистров в стек, а по окончании заберём оттуда
1 2 3 4 5 6 7 |
ENDP SYSCLK72_START PROC PUSH {R0, R1, R2, R3, LR} POP {R0, R1, R2, R3, PC} ENDP |
Также добавим для данной процедуры экспорт
1 2 |
EXPORT RCC_DEINIT EXPORT SYSCLK72_START |
А в main.s произведём импорт
1 2 |
EXTERN RCC_DEINIT EXTERN SYSCLK72_START |
Вызовем нашу подпрограмму
1 2 3 |
LDR R2, =(PERIPH_BB_BASE + (AFIO_MAPR - PERIPH_BASE) * 32 + AFIO_MAPR_SWJ_CFG_JTAGDISABLE_N * 4) STR R1, [R2] BL SYSCLK72_START |
Вернёмся в код подпрограммы SYSCLK72_START в файл rcc.s и также занесём в регистры R0 и R1 0 и 1
1 2 3 4 |
PUSH {R0, R1, R2, R3, LR} MOV R0, #0 MOV R1, #1 |
Включим HSE, дождавшись его стабилизации
1 2 3 4 5 6 7 8 9 10 |
MOV R1, #1 LDR R2, =(PERIPH_BB_BASE + (RCC_CR - PERIPH_BASE) * 32 + RCC_CR_HSEON_N * 4) STR R1, [R2] LDR R2, =RCC_CR wait_hserdy LDR R3,[R2] ; читаем регистр RCC_CR TST R3,#(1<<RCC_CR_HSERDY_N) BEQ wait_hserdy |
Теперь настройка работы с памятью FLASH. Включим буфер предварительной выборки, сначала отключив его, затем включим максимальную задержку, так как мы настраиваем максимальную частоту
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
BEQ wait_hserdy ;Enable the Prefetch Buffer ;Clear and set bit FLASH_ACR_PRFTBE in register FLASH_ACR LDR R2, =(PERIPH_BB_BASE + (FLASH_ACR - PERIPH_BASE) * 32 + FLASH_ACR_PRFTBE_N * 4) STR R0, [R2] STR R1, [R2] ;Clear field of bits FLASH_ACR_LATENCY in register FLASH_ACR LDR R2, =FLASH_ACR LDR R3, [R2] BIC R3, R3, #FLASH_ACR_LATENCY STR R3, [R2] ;Set bit FLASH_ACR_LATENCY_2 in register FLASH_ACR LDR R2, =(PERIPH_BB_BASE + (FLASH_ACR - PERIPH_BASE) * 32 + FLASH_ACR_LATENCY_2_N * 4) STR R1, [R2] |
Настроим значения всех делителей
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
STR R1, [R2] ;Clear field of bits RCC_CFGR_HPRE in register RCC_CFGR ;DIV1 LDR R2, =RCC_CFGR LDR R3, [R2] BIC R3, R3, #RCC_CFGR_HPRE STR R3, [R2] ;Clear field of bits RCC_CFGR_PPRE2 in register RCC_CFGR ;DIV1 LDR R3, [R2] BIC R3, R3, #RCC_CFGR_PPRE2 STR R3, [R2] ;Clear field of bits RCC_CFGR_PPRE1 in register RCC_CFGR LDR R3, [R2] BIC R3, R3, #RCC_CFGR_PPRE2 STR R3, [R2] ;DIV2 LDR R3, [R2] ORR R3, R3, #RCC_CFGR_PPRE1_DIV2 STR R3, [R2] LDR R3, [R2] BIC R3, R3, #RCC_CFGR_PPRE2 STR R3, [R2] |
Настроим PLL на коэффициент 9 и настроим его вход для работы от HSE
1 2 3 4 5 6 7 8 9 10 |
STR R3, [R2] ;Clear bits RCC_CFGR_PLLXTPRE and RCC_CFGR_PLLMULL in register RCC_CFGR LDR R3, [R2] BIC R3, R3, #(RCC_CFGR_PLLXTPRE + RCC_CFGR_PLLMULL) STR R3, [R2] ;Set bits RCC_CFGR_PLLSRC and RCC_CFGR_PLLMULL9 in register RCC_CFGR LDR R3, [R2] ORR R3, R3, #(RCC_CFGR_PLLSRC + RCC_CFGR_PLLMULL9) STR R3, [R2] |
Разрешим работу PLL, дождавшись затем его разблокировки
1 2 3 4 5 6 7 8 9 10 11 |
STR R3, [R2] ;Set bit RCC_CR_PLLON in register RCC_CR LDR R2, =(PERIPH_BB_BASE + (RCC_CR - PERIPH_BASE) * 32 + RCC_CR_PLLON_N * 4) STR R1, [R2] LDR R2, =RCC_CR wait_pllrdy LDR R3,[R2] ; читаем регистр RCC_CR TST R3,#RCC_CR_PLLRDY BEQ wait_pllrdy |
Выберем PLL в качестве источника системного тактирования, дождавшись затем применения данного действия
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
BEQ wait_pllrdy ;Clear field of bits RCC_CFGR_SW in register RCC_CFGR LDR R2, =RCC_CFGR LDR R3, [R2] BIC R3, R3, #RCC_CFGR_SW STR R3, [R2] ;Set bit RCC_CFGR_SW_PLL in register RCC_CFGR LDR R3, [R2] ORR R3, R3, #RCC_CFGR_SW_PLL STR R3, [R2] ;while(READ_BIT(RCC->CFGR, RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) {} wait_swsrdy LDR R3,[R2] ; читаем регистр RCC_CFGR TST R3,#RCC_CFGR_SWS BEQ wait_swsrdy |
Соберём код, прошьём контроллер и, если мы всё правильно написали, то наш светодиод будет мигать намного быстрее
Размер нашей прошивки получился всего лишь 389 байт. Если посмотреть размер аналогичной прошивки, созданной с применением CMSIS, то он составлял 1900 байт. Как вам экономия?
Итак, сегодня нам удалось настроить модуль RCC, в результате чего наш контроллер теперь работает с максимальной частотой. Всё это получилось благодаря тому, что мы изучили несколько новых команд, а также познакомились со стеком, научившись отправлять туда и забирать затем обратно данные.
Всем спасибо за внимание!
Предыдущая часть Программирование МК STM32 Следующий урок
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Смотреть ВИДЕОУРОК (нажмите на картинку)
ООО, интересные уроки 🙂
правда я кейлом не пользовался, а компилил при помощи консольного GNU AS, без среды конечно набирать было тяжко программы, но компиляцию делал батничек автоматом, так что можно было не задумываться…
кстати мигалка помоему рекордная была что то около 50 байт для F4…
Большое спасибо за урок. Много информации — 2 дня изучал.
Есть небольшие замечания по файлу rss.s
1) наверное правильнее было бы назвать файл rcc.s (несущественное)
2) в строках 32-33, 43-44, 54-55 эффективнее использовать одну команду ANDS вместо двух AND+CMP (возможно вашей целью было показать команду CMP)
3) в строке 112 надо делать BIC R3, R3, #RCC_CFGR_PPRE1 (у вас PPRE2 — опечятка?)
4) вообще, наверное, блок со 102 по 129 строки можно сильно сократить. Чего этот RCC_CR читать-писать туда-сюда? прочитали, изменили всё что надо, записали. Там же не надо ждать установки/сброса бита.
LDR R3, [R2]
BIC R3, R3, #(RCC_CFGR_HPRE)
BIC R3, R3, #(RCC_CFGR_PPRE2 + RCC_CFGR_PPRE1)
BIC R3, R3, #(RCC_CFGR_PLLXTPRE + RCC_CFGR_PLLMULL + RCC_CFGR_PLLSRC + RCC_CFGR_PLLMULL9)
ORR R3, R3, #RCC_CFGR_PPRE1_DIV2
ORR R3, R3, #(RCC_CFGR_PLLSRC + RCC_CFGR_PLLMULL9)
STR R3, [R2]
Вот только одной командой BIC всё закрыть не получилось. Везде этот гЫбкий Operand2 не даёт использовать произвольные 32-бита за одну операцию.