Jump to content
    

Всем привет, мигрирую с w3150 на w5500.

Все функции записи /чтения переписал, теперь вопрос :

функции записывают и читают без проблем в сокете 0 режим, статус итд, те можно 

поменять режим с tcp на udp и все отлично происходит а вот если попробовать 

записать и прочитать ip адрес или порт все время читаются нули.

Режим сокета close, пишу и читаю по одному регистру ( те пишем  1 байт )

режим spi с управлением по CS.

Есть такие слухи что ip адрес надо писать сразу 4 байта без сброса CS, пробовал вроде не помогло.

 

Edited by whale

Share this post


Link to post
Share on other sites

Дополню , сначала идет ресет:  SPI_Send (Wr|Comm_reg, 0, 0, 0x80); 

потом длинная пауза, 

потом все остальное.

Осцилоскопом смотрел передает все как надо,

короче загадка .... затык на ровном месте.

Edited by whale

Share this post


Link to post
Share on other sites

10 hours ago, whale said:

Есть такие слухи что ip адрес надо писать сразу 4 байта без сброса CS

Активировали CS и читаете адрес. Как вариант, гляньте на реализацию у Wiznet.

Share this post


Link to post
Share on other sites

3 hours ago, tonyk_av said:

Активировали CS и читаете адрес.

Я проверил вариант сразу читать 4 байта он оказался неверным.

Я нашел способ записывать в ip по одному регистру но работает пока через костыль а по какой причине 

пока не понял, тут прямо детектив )

Вот есть функция которая пишет/читает  в регистр

int SPI_Send (unsigned char op_code, unsigned char addr_st, unsigned char addr_ml, unsigned char data_out)
{

 
        SS_0;
 
        SPI1->DR = (addr_st<<8) | addr_ml; // работатем с 16 бит регистрами 
        while((SPI1->SR & SPI_SR_RXNE) != SPI_SR_RXNE); 
        SS = SPI1->DR;
 
        SPI1->DR = (op_code<<8) | data_out;
        while((SPI1->SR & SPI_SR_RXNE) != SPI_SR_RXNE); 
          
        SS_1; 
        
        return SPI1->DR;
         
}

Если делать так  

SPI_Send (Wr|Soket_0_reg, 0x00, 0x0C, 192);

то не пишет, если в теле функции задать data_out 

char SPI_Send (unsigned char op_code, unsigned char addr_st, unsigned char addr_ml, unsigned char data_out)
{

data_out = 192;

        SS_0;

 

то все пишет, 

смотрел по осцилографу не заметил никакой разницы  в выводе spi между ними хоть тресни. 

Регистры что по одному байту пишет по первому варианту без проблем а вот те что из нескольких байт нет.

Даже ИИ уже отчаялся )

 

Edited by whale

Share this post


Link to post
Share on other sites

Я пишу 4 байта за 1 раз, ну и плюс 3 служебных (адрес, номера сокетов), т.е. в пакете 7 байт.
Соответственно режим SPI 8 бит.
Сделал лет 10 назад, работает, с тех пор не лез, уже подзабыл подробности. Но проблем особых не было.

void Start5500WriteSocketData(dword addr, dword SocketNo, dword SocketDest, byte *Data, dword DataSize){
SockData->WData[0]=addr>>8;
SockData->WData[1]=addr;
SockData->WData[2]=(SocketNo<<5) | (SocketDest<<3) | 0x04;//control phase, write
memcpy(&SockData->WData[3], Data, DataSize);
SPI2SendRec(SockData->WData, &SockData->RData, DataSize+3, 0);
}

P.S. сигнал CS внутри SPI2SendRec опускается, и в прерывании по окончанию чтения поднимается (использую чтение как индикатор физического окончания передачи данных на шине).

Edited by alevnew

Share this post


Link to post
Share on other sites

Ну и на всяк. случай, для общей картины, пример установки IP адреса.
Только надо учитывать порядок байт в 32-хразрядном слове.

 

void Start5500WriteCommonData(dword addr, byte *Data, dword DataSize){
Start5500WriteSocketData(addr, 0, 0, Data, DataSize);
}

void WriteDReg5500(dword addr, dword val){
Start5500WriteCommonData(addr, (byte*)&val, 4);
}

//установка собственного IP 
#define adSelfIP 0x0F

 WriteDReg5500(adSelfIP, DeviceIP); 

 

Share this post


Link to post
Share on other sites

5 hours ago, whale said:

Я проверил вариант сразу читать 4 байта он оказался неверным.

А как тогда DMA работает? Он не просто по 4, а по 1444 байт за раз пишет. Не задумывались?

Share this post


Link to post
Share on other sites

Just now, tonyk_av said:

Он не просто по 4

К тому неверный что не помог в моем случае а писать там можно хоть все 16кб сразу.

Задавать ip по отдельности можно.

3 hours ago, alevnew said:

сигнал CS внутри SPI2SendRec опускается

Без этого он и работать не будет, он по CS и принимает байты в режиме vd.

Share this post


Link to post
Share on other sites

и еще вопрос: а для чего

// работатем с 16 бит регистрами

? Ведь, например, для регистров 32 или 16 бит количество передаваемых байт нечетное.
 

В общем, я делал по даташиту W5500 - все работает, как описано в даташите. Использую сразу несколько сокетов, и UDP и TCP одновременно - никаких проблем не заметил.

Share this post


Link to post
Share on other sites

Just now, alevnew said:

а для чего

spi передает быстрее в 16 битном режиме чем в 8. 

7 байт можно передать в режиме FD если прям так нужно будет.

Может мне какая отбраковка китайская попалась.

Меня больше тревожит что я сравнивал оба варианта передачи по spi по осцилу они одинаковые а по факту одна работает другая нет, чудеса.

Edited by whale

Share this post


Link to post
Share on other sites

spi передает быстрее в 16 битном режиме чем в 8.

Ну да, (((-8Ж частота SCK она ж от размерности данных зависит.
Edited by Obam

Share this post


Link to post
Share on other sites

On 7/2/2026 at 10:13 PM, Obam said:

spi передает быстрее в 16 битном режиме чем в 8.

Ну да, (((-8Ж частота SCK она ж от размерности данных зависит.

 

Может имелось ввиду, что служебных байт меньше передавать и CS лишний раз не дергать.

Вот и получается быстрей.

Share this post


Link to post
Share on other sites

1 hour ago, dimka76 said:

Может имелось ввиду

Ну вот всю интригу нарушил )

Share this post


Link to post
Share on other sites

On 7/2/2026 at 1:31 AM, whale said:

Есть такие слухи что ip адрес надо писать сразу 4 байта

У W5500 есть режимы обмена, когда можно обмениваться с ним посылками или произвольного размера, или фиксированного. Может, по ошибке записали не в тот регистр и включили не тот режим обмена?

Share this post


Link to post
Share on other sites

Вполне нормальный чип.
Накидаю-ка своих кусочков кода.
 

 

 

volatile uint8_t TX_BUF_1[8];        // Заголовок и первый байт (если один)
volatile uint8_t RX_BUF_1[8];        // Буфер под ответ (если 1 байт данных)

// Функция обменивается данными с чипом по SPI. Принимает указатель на память.
// Адрес памяти, блок регистров, Пишем или читаем, Количество данных, указатель на массив.
// Фактически все параметры собираются в первые три байта. Поле "режим обмена" - всегда 00 - переменная длина.
void w5500_SPI_TXRX(uint16_t RamAddress, uint8_t Register, uint8_t RW, uint16_t DataSize, void *DataAddress) {
    Register = Register & 0x1F;
    RW = RW & 0x01;
//     uint8_t i;
//     w5500_header = (RamAddress << 8) | (Register << 3) | (RW << 2);
    RX_BUF_1[3] = 0;
    TX_BUF_1[0] = (RamAddress >> 8);
    TX_BUF_1[1] = (RamAddress & 0xFF);
    TX_BUF_1[2] = (Register << 3) | (RW << 2);
    TX_BUF_1[3] = *((uint8_t *)DataAddress);
    SPI2->CR2 |= SPI_CR2_SSOE;                // Enable CS output.
//     SPI2->CR1 |= SPI_CR1_MSTR;                // Master mode
    SPI2->CR1 |= SPI_CR1_SPE;                // Включаем SPI2
    DMA1->LIFCR = 0x0F600000;
    DMA1->HIFCR = 0x0000003D;
    // Отправляем заголовок и до 5 байт вслед за ним (требуется для отправки данных, которые передаются через стэк).
    // Требуется для передачи настроек.
    if (DataSize == 1) {
        DMA1_Stream4->NDTR = 4;
        DMA1_Stream3->NDTR = 4;
    } else if (DataSize == 2) {
        DMA1_Stream4->NDTR = 5;
        DMA1_Stream3->NDTR = 5;
        DataAddress++;
        TX_BUF_1[4] = *((uint8_t *)DataAddress);
        DataSize--;
    } else if (DataSize == 4) {
        DataAddress++;
        TX_BUF_1[4] = *((uint8_t *)DataAddress);
        DataAddress++;
        TX_BUF_1[5] = *((uint8_t *)DataAddress);
        DataAddress++;
        TX_BUF_1[6] = *((uint8_t *)DataAddress);
        DMA1_Stream4->NDTR = 7;
        DMA1_Stream3->NDTR = 7;
        DataSize -= 3;
    }
    DMA1_Stream4->M0AR = (uint32_t)&(TX_BUF_1);
    DMA1_Stream3->M0AR = (uint32_t)&(RX_BUF_1);
    DMA1_Stream4->CR |= DMA_SxCR_MINC;
    DMA1_Stream3->CR |= DMA_SxCR_MINC;
//     SPI2->CR2 |= (SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
    DMA1_Stream3->CR |= DMA_SxCR_EN;
    DMA1_Stream4->CR |= DMA_SxCR_EN;
    while (DMA1_Stream3->CR & DMA_SxCR_EN);
    while (DMA1_Stream4->CR & DMA_SxCR_EN);
    // Сбрасываем флаги
    DMA1->LIFCR = 0x0F600000;
    DMA1->HIFCR = 0x0000003D;
    if (!RW) {
        *((uint8_t *)DataAddress++) = RX_BUF_1[3];
    }
    DataAddress++;
    DataSize--;
    if (DataSize) {
        // Если более 1 байта данных - передача будет продолжена.
        DMA1_Stream4->NDTR = DataSize;
        DMA1_Stream3->NDTR = DataSize;
        if (RW) {
            // TX
            DMA1_Stream4->M0AR = (uint32_t)DataAddress;
            DMA1_Stream3->M0AR = (uint32_t)&(DevNull);
            DMA1_Stream4->CR |= DMA_SxCR_MINC;
            DMA1_Stream3->CR &= ~(DMA_SxCR_MINC);
        } else {
            // RX
            DevNull = 0;
            DMA1_Stream4->M0AR = (uint32_t)&(DevNull);
            DMA1_Stream3->M0AR = (uint32_t)DataAddress;
            DMA1_Stream4->CR &= ~(DMA_SxCR_MINC);
            DMA1_Stream3->CR |= DMA_SxCR_MINC;
        }
        DMA1_Stream3->CR |= DMA_SxCR_EN;
        DMA1_Stream4->CR |= DMA_SxCR_EN;
        while (DMA1_Stream3->CR & DMA_SxCR_EN);
        while (DMA1_Stream4->CR & DMA_SxCR_EN);
        
    }
//     SPI2->CR2 &= ~(SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN);
    SPI2->CR1 &= ~(SPI_CR1_SPE);                // Disable SPI2
    SPI2->CR2 &= ~(SPI_CR2_SSOE);                // Disable CS output.
}
	
 



Можете взять мою реализацию драйвера (настройте интерфейс и поправьте функцию выше) и пользуйтесь. Там бОльшая часть фукнционала описана в виде функций.
Код хочет видеть объявления обратных вызовов для:

 

 

 

 

#include "w5500.h"
uint32_t System_IPAddress;
uint32_t System_NetMask;
uint32_t System_GW;
uint32_t System_ServerIP;
uint8_t System_MACAddress[6];
uint8_t LinkStatus;
uint8_t LAN_OK;
void OnConnect(uint8_t Socket) {
 // Событие при подключении к сокету
};
void OnDataReceived(uint8_t Socket, uint16_t len) {
// Приняты данные - нужно считать и обработать
};
void OnDisconnect(uint8_t Socket) {
// Подключение закрыто
    SocketClose(Socket);            // Close socket
    SocketInit(Socket, Sn_MR_PROTO_TCP, 80);
    SocketListen(Socket);
};
void OnLinkUp(uint8_t NewLinkState) {
// Линк поднялся
    uint8_t i;
    LinkStatus = NewLinkState;
    // Заглушка бага
    w5500_Init(ntohl(System_IPAddress), ntohl(System_NetMask), ntohl(System_GW), System_MACAddress);
    for (i=0;i<8;i++) {
        OnDisconnect(i);
    }
    // Like: eth0: Link up, 10M, HD / 100M, FD
};
void OnLinkDown(void) {
// Линк пропал
    LinkStatus = 0;
};
 


Естественно, нужно выполнить LanInit() и не забывать в основном цикле вызывать lan_poll() для периодического опроса чипа. Из-за своей лени пытался делать код в формате "Выстрелил и забыл".

w5500.c w5500.h

Edited by AlanDrakes

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...