Ethernet-контроллер W5300. Инициализация. Пинг

Сегодня уже интереснее. Мы с вами попробуем проинициализировать W5300 и пингануть.

Что нам для этого понадобиться:
— плата с W5300 (собственного изготовления или готовая, например WIZ830MJ);
— управляющий модуль (у меня — платка STM32F4-Discovery);
— среда разработки, дебагер, компилятор в зависимости от того, что вы выбрали в качестве управляющего модуля. (У меня – Keil. У них есть бесплатная вресия с ограничением по коду до 32 КБ. Лично мне этого более, чем достаточно.:-)) );
— сниффер. Этот пункт не обязателен, но в дальнейшем он нам понадобиться. Снифер – программка, которая будет показывать нам пакеты в сети. Мне нравится WireShark. Кстати, во время установки WireShark попросит разрешения установить WinPcap. Соглашайтесь. Если WinPcap не попросится на установку, то вам придется его устанавливать отдельно.

Схема

Обращаемся мы к памяти W5300, используя прямую адресацию и 16-битную шину данных. Принципиальную схему рисовать не буду, просто опишу, какие GPIO идут на какие ножки WIZ830MJ.

WIZ830MJ STM32F4-Discovery
Шина адреса ADDR [0:9] GPIOE [0:9]
Шина данных DATA [0:15] GPIOD [0:15]
CS GPIOB 13
RD GPIOB 14
WR GPIOB 15
RES GPIOB 11

Создаем проект в Keil

Опишу, как создать проект в Keil, если вдруг это может вызвать затруднения.

Project -> New uVision Project

Выбираем наш микроконтроллер:

Соглашаемся скопировать стартаповский файл:

В папку проекта копируем папку CMSIS, которая в свою очередь содержит файлы:

Эти файлы можно взять из STM32CubeF4
А файл system_stm32f4xx.c генерируется с помощью екселевского файла STM32F4xx_Clock_Configuration. Качаете, распаковываете и запускаете екселевский файл (UPD на момент написания статьи это был самый простой способ настройки тактирования, сейчас рекомендуется использовать CubeMX генератор кода).
Активизируете макрос, нажав кнопку параметры.

Устанавливаем значение частоты на выходе и на входе, жмем кнопочку Run, в процессе выбираем внешний источник тактирования HSE. Далее жмем Generate и в той же папке, в которой находится екселевский файл обнаруживаем system_stm32f4xx.c, сгенерированный на нашу частотку и на наши коэффициенты делителей.

Добавляем группу CMSIS в наш проект:

В группу CMSIS добавляем сишный файл из папки CMSIS:

Теперь создаем новый файл, при сохранении обзываем его main.c.

Создаем группу main, добавляем в нее только что созданный файл.
Структура проекта теперь должна быть следующей:

Сразу в опциях проекта производим следующие изменения.
Частоту устанавливаем 30 МГц:

Устанавливаем галочку Create HEX, а иначе не сможем прошивать.

Выбираем дебагер ST-Link, Settings -> Debug Port должен быть SW.

Define

Далее уже в программе прописываем адреса регистров ethernet-контроллера, кто-то делает это в хедере, кто-то в основном файле, правильнее конечно в хедере.
В общем, смотрим в даташите на W5300, там на страницах 25 – 44 расписаны адреса регистров. Нам сейчас понадобятся только эти регистры:

#define MR              0x0000  //Регистр режима
#define SHAR            0x0008  // MAC-адрес
#define SHAR2           0x000A
#define SHAR4           0x000C
#define GAR             0x0010  // IP-адрес
#define GAR2            0x0012
#define SUBR            0x0014  // маска подсети
#define SUBR2           0x0016
#define SIPR            0x0018  // IP-адрес источника при PPPoE
#define SIPR2           0x001A

Инициализация STM32F407

///////////////////////////////////////// Инициализация ///////////////////////////////////////
void Init (void)
{       // порты        
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIODEN | RCC_AHB1ENR_GPIOEEN; // вкл тактирование портов  B, E и D
        GPIOB->ODR = 0x0000F800;        // все WRC и Res выставляем в 1
        // выходы
        GPIOB->MODER = 0x55400280;              // 0-2(WRC wiznet_1), 3(RST wiznet_1)
        GPIOD->MODER = 0x55555555;              // Data         wiznet_1
        GPIOE->MODER = 0x00055555;              // Adr          wiznet 1
        // подтяжка к земле
        GPIOD->PUPDR = 0xAAAAAAAA;
        // скорость 50 МГц
        GPIOB->OSPEEDR = 0xAA8000C0;
        GPIOD->OSPEEDR = 0xAAAAAAAA;
        GPIOE->OSPEEDR = 0x000AAAAA;

        //////////////////таймер/////////////////////////////////////////////////////////////////
        RCC->APB1ENR |=RCC_APB1ENR_TIM6EN;      // вкл тактирование таймера
        TIM6->PSC=0x0000001E;                           //30, частота таймера 1 MГц,
        TIM6->CR1|=TIM_CR1_CEN;                 // вкл таймер
        TIM6->EGR|=TIM_EGR_UG;                  // вызываем событие обновления
        __NOP ();
}

Функции записи, чтения регистров W5300

В даташите приведена вот такая диаграмма, поясняющая нам процесс записи в регистры W5300:

В соответствии с ней пишем код:

// запись в регистр W5300
void WriteReg (uint16_t Addr, uint16_t Data)
{
        GPIOE->ODR = Addr;
        GPIOD->ODR = Data;
        GPIOB->ODR = 0x00005800;        // WRC
        __NOP();
        GPIOB->ODR = 0x0000F800;        // WRC
        GPIOE->ODR = 0x0000;
        GPIOD->ODR = 0x0000;
}

Точно такая же диаграмма дана для чтения из регистров.

// чтение из регистра W5300
uint16_t ReadReg (uint16_t Addr)
{
        uint16_t data;
        GPIOD->MODER = 0x00000000;      // порт для данных сделать входом
        GPIOE->ODR = Addr;
        GPIOB->ODR = 0x00009800;        // WRC
        data = GPIOD->IDR;
        GPIOB->ODR = 0x0000F800;        // WRC
        GPIOE->ODR = Addr;
        GPIOD->MODER = 0x55555555;      // порт D сделать выходом
        return (data);
}

Тут я думаю, ничего сложного.

Функция задержки

// задержка
void delay_us (uint16_t us)
{
        TIM6->CR1|=TIM_CR1_CEN; // вкл таймер
        TIM6->EGR|=TIM_EGR_UG;  // вызываем событие обновления
        while ((TIM6->CNT) < us);
        TIM6->CR1 &= ~TIM_CR1_CEN;      // выкл таймер
        TIM6->CNT=0;                    // занулить таймер
}

Инициализация W5300 и сигнал сброса

Каким должен быть по длительности сигнал сброса тоже указано в даташите:

Далее… Записываем MAC-адрес, IP-адрес, маску подсети нашего устройства, IP-адрес основного шлюза:

int main(void)
{
        Init();

        // подаем сигнал сброса на Wiznet
        GPIOB->ODR &= ~GPIO_ODR_ODR_11;
        delay_us((uint16_t) 0x0005);                    //сигнал сброса должен быть минимум 2us
        GPIOB->ODR |= GPIO_ODR_ODR_11;
        delay_us ((uint16_t) 0x00C8);           //после сброса время от 50us до  10ms

        //МАС-адрес W5300:  00.08.220.17.02.03
        WriteReg (SHAR, 0x0008);
        WriteReg (SHAR2, 0xDC11);
        WriteReg (SHAR4, 0x0203);
        //IP-адрес основного шлюза 
        WriteReg (GAR, 0xC0A8);         //192.168.70.1
        WriteReg (GAR2, 0x4601);
        //маска подсети  указывает на то, что IP-адрес класса С     255.255.255.0
        WriteReg (SUBR, 0xFFFF);
        WriteReg (SUBR2, 0xFF00);
        // IP-адрес W5300
        WriteReg (SIPR, 0xC0A8);        //192.168.70.12
        WriteReg (SIPR2, 0x460C);

        while (1) {}    
}

Компилируем, прошиваем.

Пинг

Пинг пошел и наши ICMP-пакеты тоже!

Список литературы:
1. High-Performance Internet Connectivity Solution W5300. Version 1.2.5. 2008
2. WIZ830MJ Datasheet (Ver. 1.3). 2008
3. Reference manual. STM32F405xx, STM32F407xx, STM32F415xx and STM32F417xx advanced ARM-based 32-bit MCUs. 2011
4. User Manual. STM32F4DISCOVERY. STM32F4 high-performance discovery board. 2012

Прикрепленные файлы:
Архив с папкой проекта
Исходник — main.c