/* * eth_ecat.cpp * * Created on: 16 ���. 2023 �. * Author: sychev */ #include "free_rtos/ethernet_industry/eth_ecat.hpp" #include #include namespace free_rtos { EthEcat::EthEcat(Eth& eth) : eth_{eth} , tx_flow_{*eth.getTxFlowPtr()} , telegram_{eth, ecat_timer_} , eeprom_{telegram_} { } void EthEcat::Init(TEthMacPorts port_id, uint32_t period_microsec = 250) { port_id_ = port_id; telegram_.init(port_id, period_microsec, 10); Timer::Settings ecat_tmr_sett = { .input_clk_Hz = 25000000, // 25MHz .base_address = 0x2400000u, // memory mapping, .clock_src_mux_addr = 0x430081B0u, // sysconfig .int_num = 152u, // sysconfig .int_priority = 4, // sysconfig .period_us = period_microsec /// microsec }; ecat_timer_.Init(ecat_tmr_sett); ecat_timer_.Start(); } bool EthEcat::set_slaves_to_default() { const datagram::TEcatWkc expected_wkc = 1; address::Broadcast broadcast{0x0000}; bool status; /* deact loop manual */ uint8_t a_data_out{0x00}; datagram::EcatDatagram a{ {{broadcast, ECT_REG_DLPORT}}, expected_wkc, a_data_out }; /* set IRQ mask */ uint16_t b_data_out{0x0C04}; datagram::EcatDatagram b{ {{broadcast, ECT_REG_IRQMASK}}, expected_wkc, b_data_out }; /* reset CRC counters */ std::array c_data_out; datagram::EcatDatagram> c{ {{broadcast, ECT_REG_RXERR}}, expected_wkc, c_data_out }; c_data_out.fill(0x00); /* reset FMMU's */ std::array d_data_out; datagram::EcatDatagram> d{ {{broadcast, ECT_REG_FMMU0}}, expected_wkc, d_data_out }; d_data_out.fill(0x00); /* reset SyncM */ std::array e_data_out; datagram::EcatDatagram> e{ {{broadcast, ECT_REG_SM0}}, expected_wkc, e_data_out }; e_data_out.fill(0x00); /* reset activation register */ uint8_t f_data_out{0x00}; datagram::EcatDatagram f{ {{broadcast, ECT_REG_DCSYNCACT}}, expected_wkc, f_data_out }; /* reset system time+ofs */ std::array g_data_out; datagram::EcatDatagram> g{ {{broadcast, ECT_REG_DCSYSTIME}}, expected_wkc, g_data_out }; g_data_out.fill(0x00); /* DC speedstart */ uint16_t h_data_out{0x1000}; datagram::EcatDatagram h{ {{broadcast, ECT_REG_DCSPEEDCNT}}, expected_wkc, h_data_out }; /* DC filt expr */ uint16_t i_data_out{0x0C00}; datagram::EcatDatagram i{ {{broadcast, ECT_REG_DCTIMEFILT}}, expected_wkc, i_data_out }; /* Ignore Alias register */ uint8_t j_data_out{0x00}; datagram::EcatDatagram j{ {{broadcast, ECT_REG_DLALIAS}}, expected_wkc, j_data_out }; /* Reset all slaves to Init */ uint16_t k_data_out{EC_STATE_INIT|EC_STATE_ACK}; datagram::EcatDatagram k{ {{broadcast, ECT_REG_ALCTL}}, expected_wkc, k_data_out }; /* force Eeprom from PDI */ uint8_t l_data_out{0x02}; datagram::EcatDatagram l{ {{broadcast, ECT_REG_EEPCFG}}, expected_wkc, l_data_out }; /* set Eeprom to master */ uint8_t m_data_out{0x00}; datagram::EcatDatagram m{ {{broadcast, ECT_REG_EEPCFG}}, expected_wkc, m_data_out }; auto queue = a + b + c + d + e + f + g + h + i + j + k + l + m; status = telegram_.transfer(queue); //telegram_.transfer(b); //telegram_.transfer(c); //telegram_.transfer(d); //telegram_.transfer(e); //telegram_.transfer(f); //telegram_.transfer(g); //telegram_.transfer(h); //telegram_.transfer(i); //telegram_.transfer(j); //telegram_.transfer(k); //telegram_.transfer(l); //telegram_.transfer(m); DebugP_log((char*)"Deact loop manual wkc = %d\r\n", a.get_wkc()); DebugP_log((char*)"Set IRQ mask wkc = %d\r\n", b.get_wkc()); DebugP_log((char*)"Reset CRC counters wkc = %d\r\n", c.get_wkc()); DebugP_log((char*)"Reset FMMU's wkc = %d\r\n", d.get_wkc()); DebugP_log((char*)"Reset SyncM wkc = %d\r\n", e.get_wkc()); DebugP_log((char*)"Reset activation register wkc = %d\r\n", f.get_wkc()); DebugP_log((char*)"Reset system time+ofs wkc = %d\r\n", g.get_wkc()); DebugP_log((char*)"DC speedstart wkc = %d\r\n", h.get_wkc()); DebugP_log((char*)"DC filt expr wkc = %d\r\n", i.get_wkc()); DebugP_log((char*)"Ignore Alias register wkc = %d\r\n", j.get_wkc()); DebugP_log((char*)"Reset all slaves to Init wkc = %d\r\n", k.get_wkc()); DebugP_log((char*)"Force Eeprom from PDI wkc = %d\r\n", l.get_wkc()); DebugP_log((char*)"Set Eeprom to master wkc = %d\r\n", m.get_wkc()); return status; } uint16_t EthEcat::slaves_detecting() { address::Broadcast broadcast{0x0000}; uint16_t data{0x0000}; datagram::EcatDatagram datagram{ {{broadcast, ECT_REG_TYPE}}, 1, data }; telegram_.transfer(datagram); return datagram.get_wkc(); } // Setting Station address (FP) of slave via Position addressing (AP) // Station address is datagram data bool EthEcat::set_addresses_of_slaves(uint16_t number_of_slaves, uint16_t address_base) { using TDatagram = datagram::EcatDatagram; const datagram::TEcatWkc expected_wkc = 1; std::vector datagrams; bool status; slaves_.reserve(number_of_slaves); datagrams.reserve(number_of_slaves); for(uint16_t i = 0; i < number_of_slaves; i++) { address::Position position{static_cast(-i)}; address::Station station{static_cast(address_base + i)}; address::SlaveAddresses slave_addresses{position, 0x0000, station, 0x00000000}; slaves_.emplace_back(EcatSlave{std::move(slave_addresses)}); datagrams.emplace_back(TDatagram{ {{position, ECT_REG_STADR}}, expected_wkc, slaves_.back().get_slave_address() }); } queue::Queue queue; for(uint16_t i = 0; i < number_of_slaves; i++) { queue + datagrams[i]; } status = telegram_.transfer(queue); if(status != true) { DebugP_log((char*)"Slave addresses not set\r\n"); return status; } DebugP_log((char*)"Slave addresses set\r\n"); return status; } bool EthEcat::get_addresses_of_slaves() { using TDatagram = datagram::EcatDatagram; const datagram::TEcatWkc expected_wkc = 1; std::vector datagrams; uint16_t number_of_slaves = slaves_.size(); queue::Queue queue; bool status; datagrams.reserve(number_of_slaves); for(EcatSlave& slave : slaves_) { datagrams.emplace_back(TDatagram{ {{slave.get_slave_address(), ECT_REG_STADR}}, expected_wkc, slave.get_slave_address() }); } for(uint16_t i = 0; i < number_of_slaves; i++) { queue + datagrams[i]; } status = telegram_.transfer(queue); if(status != true) { DebugP_log((char*)"Slave addresses not read\r\n"); return status; } for(EcatSlave& slave : slaves_) { DebugP_log((char*)"Slave %d address = %d\r\n", -slave.get_slave_address(), slave.get_slave_address()); } return status; } bool EthEcat::connection_test() { const datagram::TEcatWkc expected_wkc = 0; bool status; std::array test_data_out; datagram::EcatDatagram> datagram{ {{0x0000, 0x0000}}, expected_wkc, test_data_out }; test_data_out.fill(0x00); while(1) { status = telegram_.transfer(datagram); if(status != true) { break; } } return status; } bool EthEcat::config_init(uint16_t address_base) { uint16_t number_of_slaves; bool status; DebugP_log((char*)"EthercatMaster starting. Initializing slaves...\r\n"); status = set_slaves_to_default(); if(status != true) { return status; } number_of_slaves = slaves_detecting(); DebugP_log((char*)"number_of_slaves = %d\r\n", number_of_slaves); status = (number_of_slaves > 0); if(status != true) { return status; } status = set_addresses_of_slaves(number_of_slaves, address_base); if(status != true) { return status; } status = get_addresses_of_slaves(); if(status != true) { return status; } /* DebugP_log((char*)"Starting connection test...\r\n"); status = connection_test(); if(status != true) { return status; } */ return status; } bool EthEcat::enable_PDI() { const datagram::TEcatWkc expected_wkc = 1; bool status = true; for(EcatSlave& slave : slaves_) { status = (status && slave.enable_PDI(telegram_, expected_wkc)); } return status; } bool EthEcat::init_to_preop() { const datagram::TEcatWkc expected_wkc = 1; bool success = true; for(EcatSlave& slave : slaves_) { success = (success && slave.init_to_preop(telegram_, expected_wkc)); } DebugP_log((char*)"success = %d\r\n", success); return success; } bool EthEcat::preop_to_safeop() { const datagram::TEcatWkc expected_wkc = 1; bool success = true; for(EcatSlave& slave : slaves_) { success = (success && slave.preop_to_safeop(telegram_, expected_wkc)); } DebugP_log((char*)"success = %d\r\n", success); return success; } bool EthEcat::safeop_to_op() { const datagram::TEcatWkc expected_wkc = slaves_.size(); address::Broadcast broadcast{0x0000}; ALSTAT stat{0x0000, 0x0000}; uint16_t zero{0x00000000}; bool status; process_sem_.post(); if(init_sem_.pend(process_timeout_ticks_) != SystemP_SUCCESS) { DebugP_log((char*)"Process task timeout !\r\n"); return false; } { uint16_t data{EC_STATE_OPERATIONAL}; datagram::EcatDatagram datagram{ {{broadcast, ECT_REG_ALCTL}}, expected_wkc, data }; status = telegram_.transfer(datagram); if(status != true) { return status; } } process_sem_.post(); if(init_sem_.pend(process_timeout_ticks_) != SystemP_SUCCESS) { DebugP_log((char*)"Process task timeout !\r\n"); return false; } { datagram::EcatDatagram datagram{ {{broadcast, ECT_REG_ALSTAT}}, expected_wkc, stat, zero }; status = telegram_.transfer(datagram); if(status != true) { return status; } } status = (stat.state == EC_STATE_OPERATIONAL) && (stat.fault == 0); if(status != true) { DebugP_log((char*)"stat.state = %d, stat.fault = %d\r\n", stat.state, stat.fault); return status; } //DebugP_log((char*)"success = %d\r\n", success); process_sem_.post(); return status; } }