Из-за какой-то проблемы с ACPI (ошибка в ядре?) загрузка ядер 3.xx возможна только с параметром processor.nocst=1 в строке запуска ядра.
igorbounov
среда, 9 ноября 2011 г.
четверг, 10 марта 2011 г.
Настройка среды разработки
Когда уже имеется работающий копилятор, можно писать программы и собирать их с помощью командной строки, но гораздо удобнее делать все это с помощью любимой среды разработки (IDE, Integrated Development Environment).
Среда разработки
"-mthumb" - система команд, все вместе приведет к использованию семейства команд thumb-2, что в данном случае и нужно.
"-fno-exceptions" - позволяет в несколько раз уменьшить размер выходного файла, потому что выкидывается поддержка исключений для С++, которая в данном случае не нужна. Еще рекомендуют использовать параметр "-fno-rtti", который убирает накладные расходы, связанные с использованием идентификации типов во время исполнения (например, при наследовании).
"-nostartfiles" - отключается использование, например, crt0.o, где производится настройка многих вещей в самом начале работы программы: инициализация стека, настройка таблицы векторов прерываний, обнуление глобальных переменных, присвоение начальных значений. Если имеется свой собственный начальный файл. то стандартный лучше отключить.
"-nostdlib" - аналогично, если нежелательно использование стандартных библиотек libc, libm и libgcc.
Еще я на вкладке "Compiler settings-># defines" добавил следующие определения:
STM32F10X_HD
HSE_VALUE=12000000UL
Они нужны для указания параметров используемого процессора, используются стандартной библиотекой STM32.
На вкладке "Search directories" все поля пустые.
На вкладке "Pre/post build steps" в поле "Post-build steps" я добавил такие строки:
arm-none-eabi-size $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE) - чтобы получать информацию о размере используемой памяти,
arm-none-eabi-objcopy -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).hex - чтобы получить файл для прошивки,
arm-none-eabi-objcopy -O binary $(TARGET_OUTPUT_FILE) $TARGET_OUTPUT_FILE).bin - собственно, тоже можно использовать для прошивки процессора,
arm-none-eabi-objdump -h -S $(TARGET_OUTPUT_FILE) > $(TARGET_OUTPUT_FILE).lss - чтобы получить дизассемблерный листинг. Для листинга, по другим рекомендациям, можно использовать ключи -D -S - тогда листинг получается в несколько раз больше.
Создание проекта
Поскольку проект был пустой, то пришлось в нем создать новый файл main.cpp такого содержания:
SetSysClockTo72() все равно жестко используется умножение на 9:
В строке 412 и 413 файла stm32f10x.h видно, что нужны еще два файла:
Файлы core_cm3.h и core_cm3.c находятся в каталоге STM32F10x_StdPeriph_Lib_V3.3.0/Libraries/CMSIS/CM3/CoreSupport,
а system_stm32f10x.h и system_stm32f10x.c - рядом с файлом stm32f10x.h.
В core_cm3.* описывается то, что односится к ядру cortex-m3, а в остальных файлах - периферия.
Отладка
Для отладки нужно сделать следующие настройки проекта: перейти на пункт "Project->Properties...->Debugger". Здесь можно сделать настройки отладчика как для всего проекта, так и для отдельных целей сборки, я сделал для всего проекта.
Для этого в окне "Select target:" нужно выбрать "". На вкладке "Remote connection" выбрать тип "TCP", "IP address:" = localhost, "Port:" = 3333.
Перейти на вкладку "Additional GDB commands" и в поле "After connection:" вставить строки:
Для отладчика есть полезные глобальные настройки на "Settings->Compiler and debugger settings->Debugger settings". Например, такой полезный параметр: "Evaluate expression under cursor".
Среда разработки
В качестве IDE я выбрал Code::Blocks 10.05, потому что Eclipse мне разонравилось из-за своей тяжеловесности и приверженности Java.
Сначала попробовал воспользоваться встроенными в CB шаблонами проектов для ARM, но они оказались предназначенными для конкретныех отладочных плат, среди них даже не нашлось ни одной на нужном мне процессоре.
Поэтому пришлось создать пустой проект и настроить там все вручную.
Первым делом, создав пустой проект, нужно пойти на "Settings->Compiler and Debugger settings" и в разделе "Global compiler settings" выбрать GNU ARM Compilator.
Сначала нужно указать, где находятся исполняемые файлы компилятора и утилит, для этого надо перейти на вкладку "Toolchain executables" и указать там пути и названия. Автообнаружение компилятора не сработало, поэтому я руками вписал путь (/usr/arm) и ко всем утилитам ниже добавил приставку "arm-none-eabi-". Получилось очень красиво.
Еще на вкладке "Other settings" нужно выбрать значение для "Compiler logging": "Full command line", чтобы видеть в журнале компиляции все, что происходит.
На этом настройка глобальных параметров компилятора закончена.Теперь настройка сборки проекта: "Project->Build Options".
Здесь нужно в самом левом окошке выбрать название проекта, тогда настройки будут для всех вариантов сборки - и Debug, и Release.
На вкладке "Compiler settings->Other settings" вписал параметры "-mcpu=cortex-m3 -mthumb -fno-exceptions", больше никаких флагов трогать не стал. В процессорах STM32F103x нет сопроцессора, поэтому нужно использовать программный вариант арифметики с плавающей запятой (soft), что считается параметром по умолчанию.
"-mcpu=cortex-m3" - выбирается тип процессора,"-mthumb" - система команд, все вместе приведет к использованию семейства команд thumb-2, что в данном случае и нужно.
"-fno-exceptions" - позволяет в несколько раз уменьшить размер выходного файла, потому что выкидывается поддержка исключений для С++, которая в данном случае не нужна. Еще рекомендуют использовать параметр "-fno-rtti", который убирает накладные расходы, связанные с использованием идентификации типов во время исполнения (например, при наследовании).
В настроках компоновщика ("Linker settings") в поле Other linker options" нужно добавитьтакие параметры:
"-mcpu=cortex-m3 -mthumb
-Tstm32.ld
-Wl,-Map=$(TARGET_OUTPUT_FILE).map,--cref,--gc-sections".
"-Tstm32_flash.ld" - для размещения секций памяти, описанных в файле stm32_flash.ld,"-mcpu=cortex-m3 -mthumb
-Tstm32.ld
-Wl,-Map=$(TARGET_OUTPUT_FILE).map,--cref,--gc-sections".
"-Wl,-Map=$(TARGET_OUTPUT_FILE).map,--cref,--gc-sections" - чтобы получить карту памяти.
Часто встречается использование параметров
"-nostartfiles" и "-nostdlib", но это нужно делать сугубо индивидуально в зависимости от конкретной ситуации.Часто встречается использование параметров
"-nostartfiles" - отключается использование, например, crt0.o, где производится настройка многих вещей в самом начале работы программы: инициализация стека, настройка таблицы векторов прерываний, обнуление глобальных переменных, присвоение начальных значений. Если имеется свой собственный начальный файл. то стандартный лучше отключить.
"-nostdlib" - аналогично, если нежелательно использование стандартных библиотек libc, libm и libgcc.
Еще я на вкладке "Compiler settings-># defines" добавил следующие определения:
STM32F10X_HD
HSE_VALUE=12000000UL
Они нужны для указания параметров используемого процессора, используются стандартной библиотекой STM32.
На вкладке "Search directories" все поля пустые.
На вкладке "Pre/post build steps" в поле "Post-build steps" я добавил такие строки:
arm-none-eabi-size $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE) - чтобы получать информацию о размере используемой памяти,
arm-none-eabi-objcopy -O ihex $(TARGET_OUTPUT_FILE) $(TARGET_OUTPUT_FILE).hex - чтобы получить файл для прошивки,
arm-none-eabi-objcopy -O binary $(TARGET_OUTPUT_FILE) $TARGET_OUTPUT_FILE).bin - собственно, тоже можно использовать для прошивки процессора,
arm-none-eabi-objdump -h -S $(TARGET_OUTPUT_FILE) > $(TARGET_OUTPUT_FILE).lss - чтобы получить дизассемблерный листинг. Для листинга, по другим рекомендациям, можно использовать ключи -D -S - тогда листинг получается в несколько раз больше.
Создание проекта
Поскольку проект был пустой, то пришлось в нем создать новый файл main.cpp такого содержания:
#include "stm32f10x.h"
int main(void){uint32_t i = 0;while(true){for (uint32_t k = 0; k < 2000; k++)i = k;}return 0;}
Текст сделан так, чтобы компилятору можно было хоть что-то сделать. Для поддержки своих процессоров STMicroelectronics дает возможность загрузить со своего сайта библиотеку поддержки stm32f10x_stdperiph_lib.zip (примерно 14 МБ размером).
В этом пакете есть файл описания процессора STM32F10x_StdPeriph_Lib_V3.3.0/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h, в нем содержатся названия и привязки битов, регистров и всего прочего для процессора. В нем необходимо примерно в 50-й строке раскомментарить строчку, характеризующую используемый процессор, в моем случае это была строка 53:
или определить в командной строке компилятора параметр -DSTM32F10X_HD. Кроме того, необходимо указать частоту используемого кварца. По умолчанию считается, что используется кварц на 8 МГц, поэтому нужно указать свое значение (-DHSE_VALUE=12000000UL в моем случае, поскольку на плату установили кварц на 12 МГц). Но, к сожалению, этого недостаточно, потому что в функцииВ этом пакете есть файл описания процессора STM32F10x_StdPeriph_Lib_V3.3.0/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h, в нем содержатся названия и привязки битов, регистров и всего прочего для процессора. В нем необходимо примерно в 50-й строке раскомментарить строчку, характеризующую используемый процессор, в моем случае это была строка 53:
#define STM32F10X_HD /*!< STM32F10X_HD: STM32 High density devices */
SetSysClockTo72() все равно жестко используется умножение на 9:
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */что рассчитано только на использование кварца 8 МГц. В моем случае мне нужно было бы в этом файле (system_stm32f10x.h) вместо RCC_CFGR_PLLMULL9 вписать RCC_CFGR_PLLMULL6, либо написать собственную вариант настройки всех частот процессора.
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
В строке 412 и 413 файла stm32f10x.h видно, что нужны еще два файла:
поэтому их и соответствующие им С-файлы тоже нужно скопировать в свой проект.#include "core_cm3.h"#include "system_stm32f10x.h"
Файлы core_cm3.h и core_cm3.c находятся в каталоге STM32F10x_StdPeriph_Lib_V3.3.0/Libraries/CMSIS/CM3/CoreSupport,
а system_stm32f10x.h и system_stm32f10x.c - рядом с файлом stm32f10x.h.
В core_cm3.* описывается то, что односится к ядру cortex-m3, а в остальных файлах - периферия.
Периферийные описания, оказывается, можно брать и из другого каталога: STM32F10x_StdPeriph_Lib_V3.3.0/Libraries/STM32F10x_StdPeriph_Driver. Там находятся небольшие программные модули для обслуживания той или иной периферии. Но, чтобы не заморачиваться, еще и с интерфейсом этих вызовов, я использую базовую конфигурацию, а чтобы понять, как работать с тем или иным устройством процессора, заглядываю в этот каталог.
Для правильной инициализации некоторых вещей еще до передачи управления С-программе используется стартовый модуль на ассемблере, который можно взять из каталога STM32F10x_StdPeriph_Lib_V3.3.0/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/startup/gcc_ride7 (потому что компилятор Raisonance построен на базе GCC) - для процессора STM32103VCT подходит файл startup_stm32f10x_hd.s.
Но я нашел примеры стартовых файлов на С и решил использовать именно такой файл:
После сброса или подачи питания работа начинается с Reset_Handler(), который сначала инициализирует области данных, вызывает статические конструкторы, если они есть, затем заносит в регистр SCB->VTOR адрес начала таблицы векторов - без этого у меня программа упорно не хотела работать с прерываниями, и именно по этой причине я отказался от стандартного стартового файла на ассемблере, потому что он не настраивал этот регистр.
Далее вызывается функция SystemInit(), которая настраивает тактовые частоты и параметры всей системы.
И только после этого управление передается функции main().
Программа не будет работать без еще одного важного файла: командного файла для компоновщика, который я взял готовым, только подправил фактические параметры памяти.
Но я нашел примеры стартовых файлов на С и решил использовать именно такой файл:
Этот файл я назвал startup.c и включил в состав проекта. Большую часть этого файла занимает определение векторов прерываний. Они специально объявляются с помощью "#pragma weak", чтобы вместо них потом могли быть вставлены адреса фактических функций обработки прерываний. Изначально все вектора прерываний указывают на Default_Handler(), куда попадает программа в случае неправильно оформленной обработки прерывания.
#include "stm32f10x.h"
typedef void( *const intfunc )( void );
#define WEAK __attribute__ ((weak))
extern unsigned long _etext;
extern unsigned long _sidata;
extern unsigned long _sdata;
extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
extern unsigned long _estack;
void Reset_Handler(void) __attribute__((__interrupt__));
void __Init_Data(void);
void Default_Handler(void);
extern int main(void);
extern void __libc_init_array(void); /* calls CTORS of static objects */
void WEAK NMI_Handler(void);
void WEAK HardFault_Handler(void);
void WEAK MemManage_Handler(void);
void WEAK BusFault_Handler(void);
void WEAK UsageFault_Handler(void);
void WEAK MemManage_Handler(void);
void WEAK SVC_Handler(void);
void WEAK DebugMon_Handler(void);
void WEAK PendSV_Handler(void);
void WEAK SysTick_Handler(void);
void WEAK WWDG_IRQHandler(void);
void WEAK PVD_IRQHandler(void);
void WEAK TAMPER_IRQHandler(void);
void WEAK RTC_IRQHandler(void);
void WEAK FLASH_IRQHandler(void);
void WEAK RCC_IRQHandler(void);
void WEAK EXTI0_IRQHandler(void);
void WEAK EXTI1_IRQHandler(void);
void WEAK EXTI2_IRQHandler(void);
void WEAK EXTI3_IRQHandler(void);
void WEAK EXTI4_IRQHandler(void);
void WEAK DMA1_Channel1_IRQHandler(void);
void WEAK DMA1_Channel2_IRQHandler(void);
void WEAK DMA1_Channel3_IRQHandler(void);
void WEAK DMA1_Channel4_IRQHandler(void);
void WEAK DMA1_Channel5_IRQHandler(void);
void WEAK DMA1_Channel6_IRQHandler(void);
void WEAK DMA1_Channel7_IRQHandler(void);
void WEAK ADC1_2_IRQHandler(void);
void WEAK USB_HP_CAN1_TX_IRQHandler(void);
void WEAK USB_LP_CAN1_RX0_IRQHandler(void);
void WEAK CAN1_RX1_IRQHandler(void);
void WEAK CAN1_SCE_IRQHandler(void);
void WEAK EXTI9_5_IRQHandler(void);
void WEAK TIM1_BRK_IRQHandler(void);
void WEAK TIM1_UP_IRQHandler(void);
void WEAK TIM1_TRG_COM_IRQHandler(void);
void WEAK TIM1_CC_IRQHandler(void);
void WEAK TIM2_IRQHandler(void);
void WEAK TIM3_IRQHandler(void);
void WEAK TIM4_IRQHandler(void);
void WEAK I2C1_EV_IRQHandler(void);
void WEAK I2C1_ER_IRQHandler(void);
void WEAK I2C2_EV_IRQHandler(void);
void WEAK I2C2_ER_IRQHandler(void);
void WEAK SPI1_IRQHandler(void);
void WEAK SPI2_IRQHandler(void);
void WEAK USART1_IRQHandler(void);
void WEAK USART2_IRQHandler(void);
void WEAK USART3_IRQHandler(void);
void WEAK EXTI15_10_IRQHandler(void);
void WEAK RTCAlarm_IRQHandler(void);
void WEAK USBWakeUp_IRQHandler(void);
void WEAK TIM8_BRK_IRQHandler(void);
void WEAK TIM8_UP_IRQHandler(void);
void WEAK TIM8_TRG_COM_IRQHandler(void);
void WEAK TIM8_CC_IRQHandler(void);
void WEAK ADC3_IRQHandler(void);
void WEAK FSMC_IRQHandler(void);
void WEAK SDIO_IRQHandler(void);
void WEAK TIM5_IRQHandler(void);
void WEAK SPI3_IRQHandler(void);
void WEAK UART4_IRQHandler(void);
void WEAK UART5_IRQHandler(void);
void WEAK TIM6_IRQHandler(void);
void WEAK TIM7_IRQHandler(void);
void WEAK DMA2_Channel1_IRQHandler(void);
void WEAK DMA2_Channel2_IRQHandler(void);
void WEAK DMA2_Channel3_IRQHandler(void);
void WEAK DMA2_Channel4_5_IRQHandler(void);
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
(intfunc)((unsigned long)&_estack), /* The stack pointer after relocation */
Reset_Handler, /* Reset Handler */
NMI_Handler, /* NMI Handler */
HardFault_Handler, /* Hard Fault Handler */
MemManage_Handler, /* MPU Fault Handler */
BusFault_Handler, /* Bus Fault Handler */
UsageFault_Handler, /* Usage Fault Handler */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
SVC_Handler, /* SVCall Handler */
DebugMon_Handler, /* Debug Monitor Handler */
0, /* Reserved */
PendSV_Handler, /* PendSV Handler */
SysTick_Handler, /* SysTick Handler */
/* External Interrupts */
WWDG_IRQHandler, /* Window Watchdog */
PVD_IRQHandler, /* PVD through EXTI Line detect */
TAMPER_IRQHandler, /* Tamper */
RTC_IRQHandler, /* RTC */
FLASH_IRQHandler, /* Flash */
RCC_IRQHandler, /* RCC */
EXTI0_IRQHandler, /* EXTI Line 0 */
EXTI1_IRQHandler, /* EXTI Line 1 */
EXTI2_IRQHandler, /* EXTI Line 2 */
EXTI3_IRQHandler, /* EXTI Line 3 */
EXTI4_IRQHandler, /* EXTI Line 4 */
DMA1_Channel1_IRQHandler, /* DMA1 Channel 1 */
DMA1_Channel2_IRQHandler, /* DMA1 Channel 2 */
DMA1_Channel3_IRQHandler, /* DMA1 Channel 3 */
DMA1_Channel4_IRQHandler, /* DMA1 Channel 4 */
DMA1_Channel5_IRQHandler, /* DMA1 Channel 5 */
DMA1_Channel6_IRQHandler, /* DMA1 Channel 6 */
DMA1_Channel7_IRQHandler, /* DMA1 Channel 7 */
ADC1_2_IRQHandler, /* ADC1 & ADC2 */
USB_HP_CAN1_TX_IRQHandler, /* USB High Priority or CAN1 TX */
USB_LP_CAN1_RX0_IRQHandler, /* USB Low Priority or CAN1 RX0 */
CAN1_RX1_IRQHandler, /* CAN1 RX1 */
CAN1_SCE_IRQHandler, /* CAN1 SCE */
EXTI9_5_IRQHandler, /* EXTI Line 9..5 */
TIM1_BRK_IRQHandler, /* TIM1 Break */
TIM1_UP_IRQHandler, /* TIM1 Update */
TIM1_TRG_COM_IRQHandler, /* TIM1 Trigger and Commutation */
TIM1_CC_IRQHandler, /* TIM1 Capture Compare */
TIM2_IRQHandler, /* TIM2 */
TIM3_IRQHandler, /* TIM3 */
TIM4_IRQHandler, /* TIM4 */
I2C1_EV_IRQHandler, /* I2C1 Event */
I2C1_ER_IRQHandler, /* I2C1 Error */
I2C2_EV_IRQHandler, /* I2C2 Event */
I2C2_ER_IRQHandler, /* I2C2 Error */
SPI1_IRQHandler, /* SPI1 */
SPI2_IRQHandler, /* SPI2 */
USART1_IRQHandler, /* USART1 */
USART2_IRQHandler, /* USART2 */
USART3_IRQHandler, /* USART3 */
EXTI15_10_IRQHandler, /* EXTI Line 15..10 */
RTCAlarm_IRQHandler, /* RTC Alarm through EXTI Line */
USBWakeUp_IRQHandler, /* USB Wakeup from suspend */
TIM8_BRK_IRQHandler,
TIM8_UP_IRQHandler,
TIM8_TRG_COM_IRQHandler,
TIM8_CC_IRQHandler,
ADC3_IRQHandler,
FSMC_IRQHandler,
SDIO_IRQHandler,
TIM5_IRQHandler,
SPI3_IRQHandler,
UART4_IRQHandler,
UART5_IRQHandler,
TIM6_IRQHandler,
TIM7_IRQHandler,
DMA2_Channel1_IRQHandler,
DMA2_Channel2_IRQHandler,
DMA2_Channel3_IRQHandler,
DMA2_Channel4_5_IRQHandler,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0,
(intfunc)0xF1E0F85F /* @0x1E0. This is for boot in RAM mode for STM32F10x High Density devices. */
};
void __Init_Data(void) {
unsigned long *src, *dst;
/* copy the data segment into ram */
src = &_sidata;
dst = &_sdata;
if (src != dst)
while(dst < &_edata)
*(dst++) = *(src++);
/* zero the bss segment */
dst = &_sbss;
while(dst < &_ebss)
*(dst++) = 0;
}
void Reset_Handler(void) {
/* Initialize data and bss */
__Init_Data();
__libc_init_array(); // call all static construcors in C++ (harmless in C programs)
SCB->VTOR = 0x08000000;
SystemInit();
main();
while(1) {}
}
#pragma weak MMI_Handler = Default_Handler
#pragma weak MemManage_Handler = Default_Handler
#pragma weak BusFault_Handler = Default_Handler
#pragma weak UsageFault_Handler = Default_Handler
#pragma weak SVC_Handler = Default_Handler
#pragma weak DebugMon_Handler = Default_Handler
#pragma weak PendSV_Handler = Default_Handler
#pragma weak SysTick_Handler = Default_Handler
#pragma weak WWDG_IRQHandler = Default_Handler
#pragma weak PVD_IRQHandler = Default_Handler
#pragma weak TAMPER_IRQHandler = Default_Handler
#pragma weak RTC_IRQHandler = Default_Handler
#pragma weak FLASH_IRQHandler = Default_Handler
#pragma weak RCC_IRQHandler = Default_Handler
#pragma weak EXTI0_IRQHandler = Default_Handler
#pragma weak EXTI1_IRQHandler = Default_Handler
#pragma weak EXTI2_IRQHandler = Default_Handler
#pragma weak EXTI3_IRQHandler = Default_Handler
#pragma weak EXTI4_IRQHandler = Default_Handler
#pragma weak DMA1_Channel1_IRQHandler = Default_Handler
#pragma weak DMA1_Channel2_IRQHandler = Default_Handler
#pragma weak DMA1_Channel3_IRQHandler = Default_Handler
#pragma weak DMA1_Channel4_IRQHandler = Default_Handler
#pragma weak DMA1_Channel5_IRQHandler = Default_Handler
#pragma weak DMA1_Channel6_IRQHandler = Default_Handler
#pragma weak DMA1_Channel7_IRQHandler = Default_Handler
#pragma weak ADC1_2_IRQHandler = Default_Handler
#pragma weak USB_HP_CAN1_TX_IRQHandler = Default_Handler
#pragma weak USB_LP_CAN1_RX0_IRQHandler = Default_Handler
#pragma weak CAN1_RX1_IRQHandler = Default_Handler
#pragma weak CAN1_SCE_IRQHandler = Default_Handler
#pragma weak EXTI9_5_IRQHandler = Default_Handler
#pragma weak TIM1_BRK_IRQHandler = Default_Handler
#pragma weak TIM1_UP_IRQHandler = Default_Handler
#pragma weak TIM1_TRG_COM_IRQHandler = Default_Handler
#pragma weak TIM1_CC_IRQHandler = Default_Handler
#pragma weak TIM2_IRQHandler = Default_Handler
#pragma weak TIM3_IRQHandler = Default_Handler
#pragma weak TIM4_IRQHandler = Default_Handler
#pragma weak I2C1_EV_IRQHandler = Default_Handler
#pragma weak I2C1_ER_IRQHandler = Default_Handler
#pragma weak I2C2_EV_IRQHandler = Default_Handler
#pragma weak I2C2_ER_IRQHandler = Default_Handler
#pragma weak SPI1_IRQHandler = Default_Handler
#pragma weak SPI2_IRQHandler = Default_Handler
#pragma weak USART1_IRQHandler = Default_Handler
#pragma weak USART2_IRQHandler = Default_Handler
#pragma weak USART3_IRQHandler = Default_Handler
#pragma weak EXTI15_10_IRQHandler = Default_Handler
#pragma weak RTCAlarm_IRQHandler = Default_Handler
#pragma weak USBWakeUp_IRQHandler = Default_Handler
#pragma weak TIM8_BRK_IRQHandler = Default_Handler
#pragma weak TIM8_UP_IRQHandler = Default_Handler
#pragma weak TIM8_TRG_COM_IRQHandler = Default_Handler
#pragma weak TIM8_CC_IRQHandler = Default_Handler
#pragma weak ADC3_IRQHandler = Default_Handler
#pragma weak FSMC_IRQHandler = Default_Handler
#pragma weak SDIO_IRQHandler = Default_Handler
#pragma weak TIM5_IRQHandler = Default_Handler
#pragma weak SPI3_IRQHandler = Default_Handler
#pragma weak UART4_IRQHandler = Default_Handler
#pragma weak UART5_IRQHandler = Default_Handler
#pragma weak TIM6_IRQHandler = Default_Handler
#pragma weak TIM7_IRQHandler = Default_Handler
#pragma weak DMA2_Channel1_IRQHandler = Default_Handler
#pragma weak DMA2_Channel2_IRQHandler = Default_Handler
#pragma weak DMA2_Channel3_IRQHandler = Default_Handler
#pragma weak DMA2_Channel4_5_IRQHandler = Default_Handler
void Default_Handler(void) {
while (1) {}
}
После сброса или подачи питания работа начинается с Reset_Handler(), который сначала инициализирует области данных, вызывает статические конструкторы, если они есть, затем заносит в регистр SCB->VTOR адрес начала таблицы векторов - без этого у меня программа упорно не хотела работать с прерываниями, и именно по этой причине я отказался от стандартного стартового файла на ассемблере, потому что он не настраивал этот регистр.
Далее вызывается функция SystemInit(), которая настраивает тактовые частоты и параметры всей системы.
И только после этого управление передается функции main().
Программа не будет работать без еще одного важного файла: командного файла для компоновщика, который я взял готовым, только подправил фактические параметры памяти.
Отладка
Для отладки нужно сделать следующие настройки проекта: перейти на пункт "Project->Properties...->Debugger". Здесь можно сделать настройки отладчика как для всего проекта, так и для отдельных целей сборки, я сделал для всего проекта.
Для этого в окне "Select target:" нужно выбрать "
Перейти на вкладку "Additional GDB commands" и в поле "After connection:" вставить строки:
monitor reset haltПосле этого все готово для отладки. Нужно запустить openocd, а после этого можно запускать отладку: "Debugger->Start".
break main
continue
Для отладчика есть полезные глобальные настройки на "Settings->Compiler and debugger settings->Debugger settings". Например, такой полезный параметр: "Evaluate expression under cursor".
вторник, 28 декабря 2010 г.
Проблема с avrdude
После перехода на Fedora 14 при попытке обратиться к программатору:
avrdude -p m1280 -c avrispmkII -P usb
получил ошибку:
...
avrdude: usbdev_open(): error setting configuration 1: could not set config 1: Operation not permitted
Повозившись в инете, добавил в /etc/udev/rules.d файл 11-avrdude.rules
такого содержания:
Чтобы определить, какие числа нужно вставлять в поля idVendor и idProduct, нужно выполнить команду lsusb, из полученного списка устройств взять номер после ID:
и запросить более подробные сведения:
lsusb -v -d 0471:0669
Не забыть после этого добавить себя в группу (в данном случае) plugdev.
avrdude -p m1280 -c avrispmkII -P usb
получил ошибку:
...
avrdude: usbdev_open(): error setting configuration 1: could not set config 1: Operation not permitted
Повозившись в инете, добавил в /etc/udev/rules.d файл 11-avrdude.rules
такого содержания:
SUBSYSTEM=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2104", MODE="0666", GROUP="plugdev"
Чтобы определить, какие числа нужно вставлять в поля idVendor и idProduct, нужно выполнить команду lsusb, из полученного списка устройств взять номер после ID:
Bus 003 Device 002: ID 03eb:2104 Atmel Corp. AVR ISP mkII
и запросить более подробные сведения:
lsusb -v -d 0471:0669
Не забыть после этого добавить себя в группу (в данном случае) plugdev.
вторник, 16 ноября 2010 г.
Пакет средств разработки для ARM Cortex-M3
На работе решили осваивать и внедрять процессоры STM32F103x, поэтому я решил создать собственный "велосипед" - скомпилировать набор средств разработки под эту архитектуру.
Для ситуации, когда никакой операционной системы нет, а используется только "голое" железо, используется, как пишут, варианты gcc с префиксом arm-elf-* и arm-none-eabi-*. В чем разница между этими двумя вариантами, мне пока не удалось понять. Но поскольку мой проект удалось успешно скомпилировать только с помощью бесплатного CodeSorcery G++ Lite, а он использует вариант arm-none-eabi-gcc, то, видимо, и мне нужно пробовать идти этим путем.
Сборка компилятора и утилит
Для простоты я взял binutils и gcc в виде файлов src.rpm с репозитория Fedora 14. Newlib загрузил с ftp://sources.redhat.com/pub/newlib/index.html.
Порядок и параметры сборки я в основном взял отсюда:
http://www.eluaproject.net/en_tc_cortex.html,
в качестве примеров spec-файлов использовал файлы с сайтов:
http://frank.harvard.edu/~coldwell/toolchain/,
http://www.eluaproject.net/en_tc_cortex.htmlhttp://home.comcast.net/~mcatudal/,
http://mes.sourceforge.jp/mes24/linux.html,
http://www.ethernut.de/arc/,
http://michaldemin.wordpress.com/2010/02/09/arm-toolchain-newlib-part1/,
http://blog.nutaksas.com/2009/05/installing-gnuarm-arm-toolchain-on.html,
и еще кучи других мест.
Необходимо, чтобы перед сборкой в системе были установлены пакеты:
flex, flex-static, bison, mpfr, mpfr-devel, texinfo, rpm-build, gmp, gmp-devel,
libmpc, libmpc-devel. Может быть, понадобится еще что-то , но я этого не знаю, поскольку многое в системе уже было установлено по умолчанию.
1. binutils
Во всех spec-файлах я указал стандартный путь установки и цель сборки:
%define _prefix /usr/armВ готовом spec-файле заменил строчку конфигурирования:
%define _target arm-none-eabi
../configure --target=%{_target} --prefix=%{_prefix} \"--enable-interwork" я вписал на всякий случай, для cortex-m3 этого не нужно, но вдруг придется работать с другим процессором.
--enable-interwork --enable-multilib \
--with-gnu-as --with-gnu-ld \
--with-float=soft 2>&1 | tee configure.out
"--enable-multilib" - добавил, чтобы не ошибиться, вдруг разные библиотеки потребуются.
"--with-float=soft" - вынужден был добавить, иначе получались библиотеки с поддержкой VFP-команд для операций с плавающей запятой.
2. gcc
Про компилятор везде пишут, что собирать его нужно в два этапа. Сначала собирают "начальный" вариант, чтобы можно было собрать с его помощью newlib. Для сборки начального gcc используются такие параметры:
../configure --target=%{_target} --prefix=%{_prefix} \"--without-headers" - потому что пока еще нет библиотеки newlib,
--enable-languages="c,c++" \
--with-newlib \
--without-headers \
--disable-nls \
--with-gnu-as --with-gnu-ld \
--disable-shared \
--with-float=soft 2>&1 | tee configure.out
"--disable-nls" - пока еще не нужна поддержка различных человеческих языков.
Для того, чтобы появилась поддержка cortex-m3 и soft-варианта библиотек для операций с плавающей запятой, необходимо внести изменения в файл config/gcc/arm/t-arm-elf:
--- gcc/config/arm/t-arm-elf.orig 2010-09-21 18:33:40.000000000 +0400
+++ gcc/config/arm/t-arm-elf 2011-03-05 08:21:48.000000000 +0300
@@ -36,22 +36,22 @@
MULTILIB_EXCEPTIONS =
MULTILIB_MATCHES =
-#MULTILIB_OPTIONS += march=armv7
-#MULTILIB_DIRNAMES += thumb2
-#MULTILIB_EXCEPTIONS += march=armv7* marm/*march=armv7*
-#MULTILIB_MATCHES += march?armv7=march?armv7-a
-#MULTILIB_MATCHES += march?armv7=march?armv7-r
-#MULTILIB_MATCHES += march?armv7=march?armv7-m
-#MULTILIB_MATCHES += march?armv7=mcpu?cortex-a8
-#MULTILIB_MATCHES += march?armv7=mcpu?cortex-r4
-#MULTILIB_MATCHES += march?armv7=mcpu?cortex-m3
+MULTILIB_OPTIONS += march=armv7
+MULTILIB_DIRNAMES += thumb2
+MULTILIB_EXCEPTIONS += march=armv7* marm/*march=armv7*
+MULTILIB_MATCHES += march?armv7=march?armv7-a
+MULTILIB_MATCHES += march?armv7=march?armv7-r
+MULTILIB_MATCHES += march?armv7=march?armv7-m
+MULTILIB_MATCHES += march?armv7=mcpu?cortex-a8
+MULTILIB_MATCHES += march?armv7=mcpu?cortex-r4
+MULTILIB_MATCHES += march?armv7=mcpu?cortex-m3
# Not quite true. We can support hard-vfp calling in Thumb2, but how do we
# express that here? Also, we really need architecture v5e or later
# (mcrr etc).
-MULTILIB_OPTIONS += mfloat-abi=hard
-MULTILIB_DIRNAMES += fpu
-MULTILIB_EXCEPTIONS += *mthumb/*mfloat-abi=hard*
+#MULTILIB_OPTIONS += mfloat-abi=hard
+#MULTILIB_DIRNAMES += fpu
+#MULTILIB_EXCEPTIONS += *mthumb/*mfloat-abi=hard*
# MULTILIB_OPTIONS += mcpu=ep9312
# MULTILIB_DIRNAMES += ep9312
@@ -61,9 +61,9 @@
# MULTILIB_DIRNAMES += le be
# MULTILIB_MATCHES += mbig-endian=mbe mlittle-endian=mle
#
-# MULTILIB_OPTIONS += mhard-float/msoft-float
-# MULTILIB_DIRNAMES += fpu soft
-# MULTILIB_EXCEPTIONS += *mthumb/*mhard-float*
+ MULTILIB_OPTIONS += mfloat-abi=hard/mfloat-abi=soft
+ MULTILIB_DIRNAMES += fpu soft
+ MULTILIB_EXCEPTIONS += *mthumb/*mfloat-abi=hard*
#
# MULTILIB_OPTIONS += mno-thumb-interwork/mthumb-interwork
# MULTILIB_DIRNAMES += normal interwork
После сборки начального пакета gcc его нужно установить перед сборкой newlib.
3. Newlib
Здесь я использовал такие параметры сборки:
../configure --target=%{_target} --prefix=%{_prefix} \"--disable-newlib-supplied-syscalls" - этот параметр отключает целый набор стандартных системных вызовов (обращение к файлу, выделение памяти и т.д.). Поскольку зачастую эти функции очень специфичны для конкретной реализации оборудования, то нужно использовать свои вызовы или ставить хотя бы заглушки.
--enable-interwork --enable-multilib \
--disable-newlib-supplied-syscalls \
--with-float=soft 2>&1 | tee configure.out
Еще можно вставить параметр "--disable-libgloss", тогда не будет создаваться, например, библиотека crt0.o, на что будет ругаться компоновщик, и придется реализовать ее функции самостоятельно, а затем использовать при сборке программ параметры "-nostartfiles" или "-nodefaultlibs", "-nostdlib".
После сборки newlib ее нужно установить и переходить к этапу сборки полной версии gcc.
4. Полный gcc
Для этого я использовал такую конфигурацию сборки:
../configure --target=%{_target} --prefix=%{_prefix} \
--enable-interwork --enable-multilib \
--enable-languages="c,c++" --with-newlib \
--with-headers=%{_prefix}/%{_target}/include \
--disable-shared \
--with-gnu-as --with-gnu-ld \
--with-float=soft 2>&1 | tee configure.out
Здесь я указал путь к заголовкам уже установленной newlib. Но я пробовал собирать и без этого параметра, разницы не заметил.
Если установить этот пакет, то набор средств для разработки уже почти готов, осталось только собрать отладчик.
5. gdb
Тут все совсем просто:
../configure \Возможно, два последних параметра и не нужны, но мне они и не помешали пока. Можно было бы собрать gdb-tui или insight, но поскольку используемая мною IDE (Code::Blocks) отлично работает именно с gdb, к тому же мне удалось с ним поработать и непосредственно в терминальном окошке, то я ограничился простым добрым gdb.
--target=%{target} \
--prefix=%{_prefix} \
--enable-interwork --enable-multilib
Немного о вариантах сборки пакетов
Почему-то gcc и newlib, собранные с префиксом arm-elf- при тех же параметрах и патче t-arm-elf в моем проекте ругались на плавающую запятую. Компоновщик говорил, что собранные библиотеки поддерживают формат VFP, а проект нет. В общем, надо разбираться.
Информацию о получившихся библиотеках или файлах можно получить с помощью команды arm-none-eabi-readelf -a имя_файла.
Еще можно воспользоваться командой: arm-none-eabi-objdump -p файл
понедельник, 6 сентября 2010 г.
Установка драйвера NVidia для устаревшей видеоплаты
Сегодня наконец-то удалось установить драйвер для Geforce MX 440! Для этого пришлось прочитать кучу форумов.
Делал так:
1. Загрузил с сайта NVidia пакет NVIDIA-Linux-x86-96.43.18-pkg1.run.
2. В /etc/grub.conf в конец строки для загрузки ядра добавил известную
строчку "rdblacklist=nouveau".
3. В /etc/modprobe.d/ добавил файл для предотвращения загрузки nouveau (неизвестно, влияет ли это на что-нибудь):
# echo "blacklist nouveau" >> /etc/modprobe.d/blacklist-nouveau.conf
4. В /etc/inittab указал уровень загрузки 3 и перезагрузил систему.
4. После перезагрузки из командной строки запустил установку драйвера с ключом -k: sh NVIDIA*.run -k $(uname -r)
Установка на этот раз прошла без проблем.
Делал так:
1. Загрузил с сайта NVidia пакет NVIDIA-Linux-x86-96.43.18-pkg1.run.
2. В /etc/grub.conf в конец строки для загрузки ядра добавил известную
строчку "rdblacklist=nouveau".
3. В /etc/modprobe.d/ добавил файл для предотвращения загрузки nouveau (неизвестно, влияет ли это на что-нибудь):
# echo "blacklist nouveau" >> /etc/modprobe.d/blacklist-nouveau.conf
4. В /etc/inittab указал уровень загрузки 3 и перезагрузил систему.
4. После перезагрузки из командной строки запустил установку драйвера с ключом -k: sh NVIDIA*.run -k $(uname -r)
Установка на этот раз прошла без проблем.
воскресенье, 1 августа 2010 г.
Первая запись
Опять придется разбираться с драйвером WizardPen в Fedora 13. Курсор пера просто уходит в левый верхний угол и больше не движется.
Подписаться на:
Сообщения (Atom)