|
STM32F107RB + LAN8742A |
|
|
|
Mar 6 2018, 14:39
|
Группа: Участник
Сообщений: 7
Регистрация: 17-10-17
Пользователь №: 99 790

|
Приветствую всех форумчан. Столкнулся с необходимостью интеграции в проект возможности подключения по Ethernet. Микросхема PHY - LAN8742A. Сложность заключается в том, что раньше я работал только с WiFi-модулем, вся суть общения с которым в самом худшем случае - это соединение по UART, поскольку TCP/IP-стек в нем уже интегрирован. А в сложившейся ситуации нужно писать драйвер для соединение микросхемы с контроллером, а потом, насколько я понимаю, еще и драйвер подключения к TCP/IP-стеку. Использовать SPL или HAL я не хочу, поскольку до этого прекрасно обходился регистрами, но пока что все найденные мною в общем доступе примеры по работе STM-ки с этой микросхемой сделаны именно на одной из этих двух библиотек, а обсуждения на форуме по похожим темам касаются уже следующих этапов, то есть непосредственно передачи данных, до чего я пока не дошел. Суть вопроса: как написать драйвер для этой микросхемы, с чего начинать и куда смотреть? Буду благодарен за любой пинок в нужном направлении.
|
|
|
|
|
 |
Ответов
|
Mar 6 2018, 15:02
|
Группа: Участник
Сообщений: 7
Регистрация: 17-10-17
Пользователь №: 99 790

|
Цитата(scifi @ Mar 6 2018, 16:45)  У меня STM32F107RC + KSZ8081RNA, но это практически то же самое. В основной прошивке lwip, в загрузчике uIP (из-за того, что он меньше). Всё портировал сам, драйвер делал сам. Кстати, драйвер для PHY - это сильно сказано, в отдельных случаях там вообще ничего не надо делать, но обычно лучше всё-таки отслеживать подключение и отключение кабеля. У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Насколько я смог понять из найденных источников, это - самая проблемная часть. Или, если нет, то, может быть, сможете сказать, где найти какую-нибудь документацию под это дело? На сайте ST есть демонстрация работы lwIP с разными линейками, но она тоже обходит момент инициализации периферии, а больше аппноутов по этой теме я у них не нашел.
|
|
|
|
|
Mar 6 2018, 15:45
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (alexmiron31 @ Mar 6 2018, 17:02)  У Вас есть возможность продемонстрировать части кода, отвечающие за инициализацию Ethernet и описание дескрипторов DMA в самом камне? Дескрипторы: CODE namespace ethernet {
struct dma_rx_descriptor { union status { struct { uint32_t Payload_checksum_error : 1; uint32_t CRC_error : 1; uint32_t Dribble_bit_error : 1; uint32_t Receive_error : 1; uint32_t Watchdog_timeout : 1; uint32_t Is_ethernet_frame : 1; uint32_t Late_collision : 1; uint32_t IP_header_checksum_error : 1; uint32_t Last_descriptor : 1; uint32_t First_descriptor : 1; uint32_t VLAN_tag : 1; uint32_t Overflow_error : 1; uint32_t Length_error : 1; uint32_t Src_addr_filter_fail : 1; uint32_t Descriptor_error : 1; uint32_t Error_summary : 1; uint32_t Frame_length : 14; uint32_t Dst_addr_filter_fail : 1; uint32_t Owned_by_DMA : 1; }; uint32_t Raw; } Status;
union control { struct { uint32_t Buffer_size : 13; uint32_t : 1; uint32_t Is_chained : 1; uint32_t Is_last : 1; uint32_t : 13; uint32_t : 2; uint32_t : 1; }; uint32_t Raw; } Control; uint32_t volatile * pBuffer; dma_rx_descriptor volatile * pNext; };
struct dma_tx_descriptor { union status { struct { uint32_t Deferred_bit : 1; uint32_t Underflow_error : 1; uint32_t Excessive_deferral : 1; uint32_t Collision_count : 4; uint32_t VLAN_frame : 1; uint32_t Excessive_collision : 1; uint32_t Late_collision : 1; uint32_t No_carrier : 1; uint32_t Loss_of_carrier : 1; uint32_t IP_payload_error : 1; uint32_t Frame_flushed : 1; uint32_t Jabber_timeout : 1; uint32_t Error_summary : 1; uint32_t IP_header_error : 1; uint32_t Tx_timestamp_status : 1; uint32_t : 2; uint32_t Is_chained : 1; uint32_t Is_end_of_ring : 1; uint32_t Checksum_insertion : 2; uint32_t : 1; uint32_t Tx_timestamp_enable : 1; uint32_t Disable_pad : 1; uint32_t Disable_CRC : 1; uint32_t First_segment : 1; uint32_t Last_segment : 1; uint32_t Interrupt_on_completion: 1; uint32_t Owned_by_DMA : 1; }; uint32_t Raw; } Status; uint32_t Byte_count : 13;
uint32_t volatile * pBuffer; dma_tx_descriptor volatile * pNext; };
template<typename descriptor, size_t max_packet_size> struct dma_chain { descriptor volatile Descriptor; uint32_t volatile Data[(max_packet_size + sizeof(uint32_t) - 1) / sizeof(uint32_t)]; };
template<size_t packet_size> uintptr_t init_descriptors_chain(dma_chain<dma_tx_descriptor, packet_size> * pChain, size_t elements) { auto pElement = pChain; do { pElement->Descriptor.pBuffer = pElement->Data; pElement->Descriptor.pNext = &pElement[1].Descriptor; dma_tx_descriptor::status Status = {}; Status.Is_chained = true; /* Setting the last segment and first segment bits (in this case a frame is transmitted in one descriptor) */ Status.First_segment = true; Status.Last_segment = true; Status.Checksum_insertion = 3; // IP header, payload, pseudo-header pElement++->Descriptor.Status.Raw = Status.Raw; } while(--elements); pElement[-1].Descriptor.pNext = &pChain->Descriptor; return (uintptr_t)&pChain->Descriptor; }
template<size_t packet_size> uintptr_t init_descriptors_chain(dma_chain<dma_rx_descriptor, packet_size> * pChain, size_t elements) { auto pElement = pChain; do { dma_rx_descriptor::status Status = {}; Status.Owned_by_DMA = true; pElement->Descriptor.Status.Raw = Status.Raw;
dma_rx_descriptor::control Control = {}; Control.Buffer_size = packet_size; Control.Is_chained = true; pElement->Descriptor.Control.Raw = Control.Raw; pElement->Descriptor.pBuffer = pElement->Data; pElement->Descriptor.pNext = &pElement[1].Descriptor; ++pElement; } while(--elements); pElement[-1].Descriptor.pNext = &pChain->Descriptor; return (uintptr_t)&pChain->Descriptor; }
template<typename T> inline uintptr_t init_descriptors_chain(T & buffer) { return init_descriptors_chain(buffer, sizeof(buffer) / sizeof(buffer[0])); }
} // namespace ethernet
Объявление: CODE #define ETH_MAX_PACKET_SIZE 1520 /*!< ETH_HEADER + ETH_EXTRA + MAX_ETH_PAYLOAD + ETH_CRC */
namespace ethernet { static dma_chain<dma_rx_descriptor, ETH_MAX_PACKET_SIZE> Rx_buffer[ETH_RXBUFNB]; static dma_chain<dma_tx_descriptor, ETH_MAX_PACKET_SIZE> Tx_buffer[ETH_TXBUFNB];
static dma_tx_descriptor volatile * Tx_next = &Tx_buffer[0].Descriptor; static dma_rx_descriptor volatile * Rx_last = &Rx_buffer[0].Descriptor; Инициализация: CODE err_t stm32_if_init(struct netif *netif) { LWIP_ASSERT("netif != NULL", (netif != NULL)); /* * Initialize the snmp variables and counters inside the struct netif. * The last argument should be replaced with your link speed, in units * of bits per second. */ // NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000);
/* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; netif->linkoutput = stm32_if_output;
/* initialize the hardware */ /* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* maximum transfer unit */ netif->mtu = 1500; /* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
lan8720a::init();
while(ETH->DMABMR & ETH_DMABMR_SR) ; /* set MAC hardware address */ ETH->MACA0HR = 0 | (netif->hwaddr[5] << 8) | (netif->hwaddr[4] << 0) ; ETH->MACA0LR = 0 | (netif->hwaddr[3] << 24) | (netif->hwaddr[2] << 16) | (netif->hwaddr[1] << 8) | (netif->hwaddr[0] << 0) ;
ETH->MACFFR = 0 | 0 * ETH_MACFFR_RA // Receive all | 0 * ETH_MACFFR_HPF // Hash or perfect filter | 0 * ETH_MACFFR_SAF // Source address filter | 0 * ETH_MACFFR_SAIF // SA inverse filtering | 1 * ETH_MACFFR_PCF // Pass control frames: // 1: MAC filters all control frames from reaching the application // 2: MAC forwards all control frames to application even if they fail the Address Filter // 3: MAC forwards control frames that pass the Address Filter | 0 * ETH_MACFFR_BFD // Broadcast frame disable | 0 * ETH_MACFFR_PAM // Pass all multicast | 0 * ETH_MACFFR_DAIF // DA Inverse filtering | 0 * ETH_MACFFR_HM // Hash multicast | 0 * ETH_MACFFR_HU // Hash unicast | 0 * ETH_MACFFR_PM // Promiscuous mode ; // Hash table ETH->MACHTHR = 0; ETH->MACHTLR = 0;
ETH->MACFCR = 0 | 0 * (ETH_MACFCR_PT & -ETH_MACFCR_PT) // Pause time | 1 * ETH_MACFCR_ZQPD // Zero-quanta pause disable | 0 * (ETH_MACFCR_PLT & -ETH_MACFCR_PLT)// Pause low threshold: // 0: Pause time minus 4 slot times // 1: Pause time minus 28 slot times // 2: Pause time minus 144 slot times // 3: Pause time minus 256 slot times | 0 * ETH_MACFCR_UPFD // Unicast pause frame detect | 1 * ETH_MACFCR_RFCE // Receive flow control enable | 1 * ETH_MACFCR_TFCE // Transmit flow control enable | 0 * ETH_MACFCR_FCBBPA // Flow control busy/backpressure activate ;
ETH->MACVLANTR = 0 | 0 * ETH_MACVLANTR_VLANTC // 12-bit VLAN tag comparison | 0 * (ETH_MACVLANTR_VLANTI & -ETH_MACVLANTR_VLANTI) // VLAN tag identifier ;
/* Initialize Tx Descriptors list: Chain Mode */ ETH->DMATDLAR = init_descriptors_chain(Tx_buffer); /* Initialize Rx Descriptors list: Chain Mode, owned by DMA, ints enabled */ ETH->DMARDLAR = init_descriptors_chain(Rx_buffer);
ETH->DMABMR = 0 | 1 * ETH_DMABMR_AAB // Address-aligned beats | 0 * ETH_DMABMR_FPM // 4xPBL mode | 0 * ETH_DMABMR_USP // Use separate PBL | 1 * (ETH_DMABMR_RDP & -ETH_DMABMR_RDP) // RxDMA programmable burst length, must be 2^n | 0 * ETH_DMABMR_FB // Fixed burst | 0 * (ETH_DMABMR_RTPR & -ETH_DMABMR_RTPR) // Rx/Tx priority ratio | 1 * (ETH_DMABMR_PBL & -ETH_DMABMR_PBL) // TxDMA (or both) programmable burst length | 0 * ETH_DMABMR_DSL // Descriptor Skip Length | 0 * ETH_DMABMR_DA // DMA arbitration scheme: 0 - roubd-robbin, 1 - rx priority | 0 * ETH_DMABMR_SR // Software reset ;
/* Enable MAC transmission and reception*/ ETH->MACCR = 0 | 0 * ETH_MACCR_WD // Watchdog disabling | 0 * ETH_MACCR_JD // Jabber disabling | 0 * (ETH_MACCR_IFG & -ETH_MACCR_IFG) // Inter-frame gap | 0 * ETH_MACCR_CSD // Carrier sense disabling | 1 * ETH_MACCR_FES // Fast ethernet speed | 0 * ETH_MACCR_ROD // Receive own disabling | 0 * ETH_MACCR_LM // loopback mode | 1 * ETH_MACCR_DM // Duplex mode | 0 * ETH_MACCR_IPCO // IP Checksum offload | 0 * ETH_MACCR_RD // Retry disable | 0 * ETH_MACCR_APCS // Automatic Pad/CRC stripping | 0 * (ETH_MACCR_BL &-ETH_MACCR_BL) // Back-off limit: random integer number ® of slot time delays before rescheduling // a transmission attempt during retries after a collision: 0 =< r <2^k | 0 * ETH_MACCR_DC // Defferal check | 1 * ETH_MACCR_TE // Transmitter enable | 1 * ETH_MACCR_RE // Receiver enable ; /* Flush Transmit FIFO, enable DMA transmission and DMA reception */ ETH->DMAOMR = 0 | 1 * ETH_DMAOMR_DTCEFD // Disabling dropping of TCP/IP checksum error frames | 1 * ETH_DMAOMR_RSF // Receive store and forward | 1 * ETH_DMAOMR_DFRF // Disabling flushing of received frames | 1 * ETH_DMAOMR_TSF // Transmit store and forward Mandatory for hardware CRC calc. | 0 * ETH_DMAOMR_FTF // Flush transmit FIFO | 0 * (ETH_DMAOMR_TTC & -ETH_DMAOMR_TTC)// Transmit threshold control: // 0: 64 Bytes // 1: 128 Bytes // 2: 192 Bytes // 3: 256 Bytes // 4: 40 Bytes // 5: 32 Bytes // 6: 24 Bytes // 7: 16 Bytes | 1 * ETH_DMAOMR_ST // Start/stop transmission command | 0 * ETH_DMAOMR_FEF // Forward error frames | 0 * ETH_DMAOMR_FUGF // Forward undersized good frames | 0 * (ETH_DMAOMR_RTC & -ETH_DMAOMR_RTC)// receive threshold control // 0: 64 Bytes // 1: 32 Bytes // 2: 96 Bytes // 3: 128 Bytes | 0 * ETH_DMAOMR_OSF // operate on second frame | 1 * ETH_DMAOMR_SR // Start/stop receive ; etharp_init(); sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE; // enable receive interrupt
return ERR_OK; }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|