§
|
> Адаптация демонстрационного программного проекта |
В качестве базового примера программного проекта используется демонстрационный проект AN3102 от ST Microelectronics с использованием библиотеки стандартной периферии и драйвера Ethernet от ST и открытого стека TCP/IP lwIP, разработанного Adam Dunkels. Проект предназначен для запуска на отладочной плате STM3210C от STMicroelectronics и реализован без использования RTOS.
Проект реализует следующие функции: - DHCP-клиент с выводом полученного IP-адреса на графический LCD.
- Web-сервер с управлением четырьмя светодиодами отладочной платы и индикацией уровня сигнала на входе канала АЦП.
- "Hello world” – приложение на базе telnet-сервера, отвечающее на введенный пользователем текст.
- TFTP-сервер на базе SD-Card
- Клиент-серверное приложение, позволяющее управлять светодиодами одной отладочной платы с помощью сенсорного экрана другой аналогичной платы.
Для переноса проекта на наше устройство рассмотрим его отличия от платы STM3210C.
1. Используется МК в 64-выводном корпусе, интерфейс RMII подключен без использования ремаппинга выводов.
2. Используется микросхема PHY ST802RT1, вместо DP83848 – это ключевое отличие нашего устройства и ему будет уделено особое внимание.
3. Используется три светодиода, подключенных к линиям PB0, PB1, PB5. Активный уровень – лог 0.
4. Вывод МК ADC12_IN14 занят интерфейсом RMII, для демонстрации АЦП будем использовать свободный вывод ADC12_IN3.
5. Отсутствует подключение SD-Card по SPI.
6. Отсутствует графический LCD и сенсорный экран.
7. Отсутствует внешний расширитель портов ввода-вывода (IO-Extender).
Рассмотрим структуру проекта на примере версии для IAR EWARM v5. В состав проекта входят следующие группы исходного кода:
- CMSIS – библиотека поддержки платформы Cortex M3.
- efsl – библиотека поддержки файловой системы FAT и обмена с SD-Card по SPI.
- ETHLib – библиотека драйвера контроллера Ethernet.
- EWARMv5 – стартовый ассемблерный код от IAR.
- FWLib – библиотека поддержки стандартной периферии STM32.
- LwIP – стек протоколов TCP/IP (lwIP).
- STM32_EVAL – библиотека поддержки периферии отладочной платы.
- User – пользовательские приложения.
Раскроем список файлов User и рассмотрим его более детально:
- client.c – реализация клиентского приложения.
- helloworld.c – реализация сервера Telnet.
- httpd.c – реализация Web-сервера.
- main.c – основной модуль программы.
- netconf.c – выбор конфигурации клиент/сервер и IP-адреса.
- server.c – реализация серверного приложения.
- stm32f107.c – функции инициализации периферии МК.
- stm32f107_it.c – пользовательские обработчики прерываний.
- tftpserver.c – реализация TFTP-сервера.
- tftputils.c – поддержка протокола TFTP.
Далее начнем модификацию проекта по следующему плану:
- Удаление неиспользуемых модулей.
- Контрольная компиляция.
- Корректировка функций поддержки периферии отладочной платы.
- Корректировка функций инициализации периферии МК.
- Корректировка функций инициализации PHY.
- Настройка стека lwIP.
- Компиляция и проверка на устройстве.
§
|
> Удаление неиспользуемых модулей |
Для упрощения задачи и по причине отсутсвия аппаратной поддержки, удалим из проекта следующие модули: TFTP-сервер (tftpserver.c, tftputils.c), клиент-серверное приложение (client.c, server.c), файловую систему (группа efsl), поддержку LCD (stm3210c_eval_lcd.c), поддержку расширителя ввода-вывода (stm3210c_eval_ioe.c). Из модуля stm32f107_it.c удаляем функцию обработчик прерывания от расширителя ввода-вывода void EXTI15_10_IRQHandler(void). Теперь нужно "заглушить” обращения к функциям графического LCD. Проще всего это сделать, подключив к проекту файл с набором пустых функций, совпадающих по именам с функциями из файла stm3210c_eval_lcd.c. В будущем, вывод на LCD можно будет перенаправить в UART или на символьный LCD (HD44780), написав соответствующие функции. Файл patch_lcd.c
#include "stm3210c_eval_lcd.h"
void LCD_DisplayStringLine(uint8_t Line, uint8_t *ptr) {}
void LCD_SetTextColor(__IO uint16_t Color) {}
void LCD_SetBackColor(__IO uint16_t Color)
{}
void LCD_DrawRect(uint8_t Xpos, uint16_t Ypos, uint8_t Height, uint16_t Width)
{}
void LCD_Clear(uint16_t Color)
{}
Далее найдем обращения к функциям инициализации модулей, удаленных из проекта. Из файла main.c необходимо удалить вызов tftpd_init(), из файла stm32f107.c – вызов STM3210C_LCD_Init(), из файла netconf.c – вызовы server_init(), IOE_Config(), IOE_ITConfig(IOE_ITSRC_TSC), client_init(). После этого необходимо скомпилировать проект, чтобы убедиться, что ошибок на стадиях компиляции и линковки в нем нет.
§
|
> Корректировка функций поддержки периферии отладочной платы |
На следующем этапе необходимо настроить библиотеку поддержки отладочной платы для корректной работы светодиодов, кнопок и USART. В нашем устройстве кнопки и светодиоды подключены к следующим линиям:
LED1 – PB0
LED2 – PB1
LED3 – PB5
KEY1 – PC0
KEY3 – PC2
KEY4 – PC3
На плате STM3210C имеется также светодиод LED4, который в нашем устройстве виртуально объединяется с LED1. Также настроим COM-порт на USART1 (RXD1 – PA10, TXD1 – PA9). Настройка производится модификацией файла stm3210c_eval.h :
#define LEDn 4
#define LED1_GPIO_PORT GPIOB
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED1_GPIO_PIN GPIO_Pin_0
#define LED2_GPIO_PORT GPIOB
#define LED2_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED2_GPIO_PIN GPIO_Pin_1
#define LED3_GPIO_PORT GPIOB
#define LED3_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED3_GPIO_PIN GPIO_Pin_5
#define LED4_GPIO_PORT GPIOB
#define LED4_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED4_GPIO_PIN GPIO_Pin_0 //Совпадает с LED1
#define BUTTONn 3 /*!< Joystick pins are connected to an IO Expander (accessible through I2C1 interface) */
#define WAKEUP_BUTTON_PORT GPIOC
#define WAKEUP_BUTTON_CLK RCC_APB2Periph_GPIOC
#define WAKEUP_BUTTON_PIN GPIO_Pin_0
#define WAKEUP_BUTTON_EXTI_LINE EXTI_Line0
#define WAKEUP_BUTTON_PORT_SOURCE GPIO_PortSourceGPIOC
#define WAKEUP_BUTTON_PIN_SOURCE GPIO_PinSource0
#define WAKEUP_BUTTON_IRQn EXTI0_IRQn
#define TAMPER_BUTTON_PORT GPIOC
#define TAMPER_BUTTON_CLK RCC_APB2Periph_GPIOC
#define TAMPER_BUTTON_PIN GPIO_Pin_2
#define TAMPER_BUTTON_EXTI_LINE EXTI_Line2
#define TAMPER_BUTTON_PORT_SOURCE GPIO_PortSourceGPIOC
#define TAMPER_BUTTON_PIN_SOURCE GPIO_PinSource2
#define TAMPER_BUTTON_IRQn EXTI2_IRQn
#define KEY_BUTTON_PORT GPIOC
#define KEY_BUTTON_CLK RCC_APB2Periph_GPIOC
#define KEY_BUTTON_PIN GPIO_Pin_3
#define KEY_BUTTON_EXTI_LINE EXTI_Line3
#define KEY_BUTTON_PORT_SOURCE GPIO_PortSourceGPIOC
#define KEY_BUTTON_PIN_SOURCE GPIO_PinSource3
#define KEY_BUTTON_IRQn EXTI3_IRQn
#define COMn 1
#define EVAL_COM1 USART1
#define EVAL_COM1_GPIO GPIOA
#define EVAL_COM1_CLK RCC_APB2Periph_USART1
#define EVAL_COM1_GPIO_CLK RCC_APB2Periph_GPIOA
#define EVAL_COM1_RxPin GPIO_Pin_10
#define EVAL_COM1_TxPin GPIO_Pin_9 При рассмотрении отличий нашего устройства от платы STM3210C было отмечено, что светодиоды включаются уровнем логического нуля. Для корректной работы необходимо исправить в файле stm32_eval.c функции:
void STM_EVAL_LEDOn(Led_TypeDef Led)
{
// GPIO_PORT[Led]->BSRR = GPIO_PIN[Led];
GPIO_PORT[Led]->BRR = GPIO_PIN[Led]; // Установка бита в 0
}
void STM_EVAL_LEDOff(Led_TypeDef Led)
{
//GPIO_PORT[Led]->BRR = GPIO_PIN[Led];
GPIO_PORT[Led]->BSRR = GPIO_PIN[Led];
// Установка бита в 1
}
В инициализации USART необходимо исправить:
#elif defined (USE_STM3210C_EVAL)
if (COM == COM1)
{
/* Enable the USART2 Pins Software Remapping */
//GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);
//RCC_APB1PeriphClockCmd(COM_USART_CLK[COM], ENABLE);
RCC_APB2PeriphClockCmd(COM_USART_CLK[COM], ENABLE); //USART1 на APB2!
}
#endif
§
|
> Корректировка функций инициализации периферии МК |
Функции инициализации периферии МК размещены в файле stm32f107.c и вызываются через функцию System_Setup(). Здесь нужно исправить настройку на USART1.
//* Enable USART2 clock */
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
Номер канала АЦП задается в функции ADC_Configuration(). Изменим его следующим образом:
/* ADC1 regular channel14 configuration */
// ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_13Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_13Cycles5);
Функция GPIO_Configuration() задает режимы работы выводов МК, используемых для Ethernet и АЦП. Здесь следует обратить внимание на то, что RMII используется без ремаппинга, а порт GPIOD в нашем устройстве отсутствует вообще. В результате код будет выглядеть следующим образом:
void GPIO_Configuration(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* ETHERNET pins configuration */
/* AF Output Push Pull:
- ETH_MII_MDIO / ETH_RMII_MDIO: PA2
- ETH_MII_MDC / ETH_RMII_MDC: PC1
- ETH_MII_TXD2: PC2 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_TX_EN / ETH_RMII_TX_EN: PB11
- ETH_MII_TXD0 / ETH_RMII_TXD0: PB12
- ETH_MII_TXD1 / ETH_RMII_TXD1: PB13
- ETH_MII_PPS_OUT / ETH_RMII_PPS_OUT: PB5 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_TXD3: PB8 - НЕ ИСПОЛЬЗУЕТСЯ! */
/* Configure PA2 as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure PC1, PC2 and PC3 as alternate function push-pull */
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Configure PB5, PB8, PB11, PB12 and PB13 as alternate function push-pull */
//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_11 |
// GPIO_Pin_12 | GPIO_Pin_13;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/**************************************************************/
/* For Remapped Ethernet pins */
/*************************************************************/
/* Input (Reset Value):
- ETH_MII_CRS CRS: PA0 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_RX_CLK / ETH_RMII_REF_CLK: PA1
- ETH_MII_COL: PA3 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_RX_DV / ETH_RMII_CRS_DV: PD8 -> PA7
- ETH_MII_TX_CLK: PC3 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_RXD0 / ETH_RMII_RXD0: PD9 -> PC4
- ETH_MII_RXD1 / ETH_RMII_RXD1: PD10 -> PC5
- ETH_MII_RXD2: PD11 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_RXD3: PD12 - НЕ ИСПОЛЬЗУЕТСЯ!
- ETH_MII_RX_ER: PB10 - НЕ ИСПОЛЬЗУЕТСЯ!
- PHY_INT: PA6
*/
/* ETHERNET pins remapp in STM3210C-EVAL board: RX_DV and RxD[3:0] */
// GPIO_PinRemapConfig(GPIO_Remap_ETH, ENABLE); //Ремап не используется!
/* Configure PA0, PA1 and PA3 as input */
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure PB10 as input */
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
// GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure PC3 as input */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Configure PD8, PD9, PD10, PD11 and PD12 as input */
// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
// GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
// GPIO_Init(GPIOD, &GPIO_InitStructure); /**/
/* ADC Channel14 config --------------------------------------------------------*/
/* Relative to STM3210D-EVAL Board */
/* Configure PC.04 (ADC Channel14) as analog input -------------------------*/
// PA3 - ADC1 CH03
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* MCO pin configuration------------------------------------------------- */
/* Configure MCO (PA8) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure); }
Следующий шаг – инициализация Ethernet, производится в функции Ethernet_Configuration(). Необходимо проверить в начале файла stm32f107.c наличие строк:
#define DP83848_PHY /* Ethernet pins mapped on STM3210C-EVAL Board */
#define PHY_ADDRESS 0x01 /* Relative to STM3210C-EVAL Board */
//#define MII_MODE /* MII mode for STM3210C-EVAL Board (MB784) (check jumpers setting) */
#define RMII_MODE /* RMII mode for STM3210C-EVAL Board (MB784) (check jumpers setting) */
Микросхема ST802RT1 по умолчанию имеет адрес на канале управления равный 1, этот адрес должен быть определен в константе PHY_ADDRESS. Определение RMII_MODE означает, что инициализацию Ethernet нужно производить для режима RMII, в том числе необходимо включить генерацию частоты 50МГц с помощью PLL3 на выход MCO. Инициализация Ethernet не требует корректировок, за исключением настройки PHY, о которой будет подробно рассказано в следующей части статьи.
|