whale 1 July 1 Posted July 1 (edited) · Report post Всем привет, мигрирую с w3150 на w5500. Все функции записи /чтения переписал, теперь вопрос : функции записывают и читают без проблем в сокете 0 режим, статус итд, те можно поменять режим с tcp на udp и все отлично происходит а вот если попробовать записать и прочитать ip адрес или порт все время читаются нули. Режим сокета close, пишу и читаю по одному регистру ( те пишем 1 байт ) режим spi с управлением по CS. Есть такие слухи что ip адрес надо писать сразу 4 байта без сброса CS, пробовал вроде не помогло. Edited July 1 by whale Quote Share this post Link to post Share on other sites More sharing options...
whale 1 July 1 Posted July 1 (edited) · Report post Дополню , сначала идет ресет: SPI_Send (Wr|Comm_reg, 0, 0, 0x80); потом длинная пауза, потом все остальное. Осцилоскопом смотрел передает все как надо, короче загадка .... затык на ровном месте. Edited July 1 by whale Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 80 July 2 Posted July 2 · Report post 10 hours ago, whale said: Есть такие слухи что ip адрес надо писать сразу 4 байта без сброса CS Активировали CS и читаете адрес. Как вариант, гляньте на реализацию у Wiznet. Quote Share this post Link to post Share on other sites More sharing options...
whale 1 July 2 Posted July 2 (edited) · Report post 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 July 2 by whale Quote Share this post Link to post Share on other sites More sharing options...
alevnew 2 July 2 Posted July 2 (edited) · Report post Я пишу 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 July 2 by alevnew Quote Share this post Link to post Share on other sites More sharing options...
alevnew 2 July 2 Posted July 2 · Report post Ну и на всяк. случай, для общей картины, пример установки 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); Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 80 July 2 Posted July 2 · Report post 5 hours ago, whale said: Я проверил вариант сразу читать 4 байта он оказался неверным. А как тогда DMA работает? Он не просто по 4, а по 1444 байт за раз пишет. Не задумывались? Quote Share this post Link to post Share on other sites More sharing options...
whale 1 July 2 Posted July 2 · Report post Just now, tonyk_av said: Он не просто по 4 К тому неверный что не помог в моем случае а писать там можно хоть все 16кб сразу. Задавать ip по отдельности можно. 3 hours ago, alevnew said: сигнал CS внутри SPI2SendRec опускается Без этого он и работать не будет, он по CS и принимает байты в режиме vd. Quote Share this post Link to post Share on other sites More sharing options...
alevnew 2 July 2 Posted July 2 · Report post и еще вопрос: а для чего // работатем с 16 бит регистрами ? Ведь, например, для регистров 32 или 16 бит количество передаваемых байт нечетное. В общем, я делал по даташиту W5500 - все работает, как описано в даташите. Использую сразу несколько сокетов, и UDP и TCP одновременно - никаких проблем не заметил. Quote Share this post Link to post Share on other sites More sharing options...
whale 1 July 2 Posted July 2 (edited) · Report post Just now, alevnew said: а для чего spi передает быстрее в 16 битном режиме чем в 8. 7 байт можно передать в режиме FD если прям так нужно будет. Может мне какая отбраковка китайская попалась. Меня больше тревожит что я сравнивал оба варианта передачи по spi по осцилу они одинаковые а по факту одна работает другая нет, чудеса. Edited July 2 by whale Quote Share this post Link to post Share on other sites More sharing options...
Obam 54 July 2 Posted July 2 (edited) · Report post spi передает быстрее в 16 битном режиме чем в 8. Ну да, (((-8Ж частота SCK она ж от размерности данных зависит. Edited July 2 by Obam Quote Share this post Link to post Share on other sites More sharing options...
dimka76 99 July 2 Posted July 2 · Report post On 7/2/2026 at 10:13 PM, Obam said: spi передает быстрее в 16 битном режиме чем в 8. Ну да, (((-8Ж частота SCK она ж от размерности данных зависит. Может имелось ввиду, что служебных байт меньше передавать и CS лишний раз не дергать. Вот и получается быстрей. Quote Share this post Link to post Share on other sites More sharing options...
whale 1 July 2 Posted July 2 · Report post 1 hour ago, dimka76 said: Может имелось ввиду Ну вот всю интригу нарушил ) Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 80 July 3 Posted July 3 · Report post On 7/2/2026 at 1:31 AM, whale said: Есть такие слухи что ip адрес надо писать сразу 4 байта У W5500 есть режимы обмена, когда можно обмениваться с ним посылками или произвольного размера, или фиксированного. Может, по ошибке записали не в тот регистр и включили не тот режим обмена? Quote Share this post Link to post Share on other sites More sharing options...
AlanDrakes 6 July 3 Posted July 3 (edited) · Report post Вполне нормальный чип. Накидаю-ка своих кусочков кода. 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 July 3 by AlanDrakes Quote Share this post Link to post Share on other sites More sharing options...