Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
LPC1769Emac.cpp
00001 #include "LPC1769Emac.h" 00002 #include <LPC1768/ARM/cmsis.h> 00003 #include <mbed.h> 00004 #include "LAN8710AReg.h" 00005 #include "LPC1769Reg.h" 00006 #include "Frame.h" 00007 00008 #define BUFFER_SECTION __attribute((section("AHBSRAM1"),aligned(8))) 00009 00010 #define SET_EMAC_BIT(NAME, PATTERN) (LPC_EMAC->NAME = PATTERN} 00011 #define ENABLE_EMAC_BIT(NAME, MASK) (LPC_EMAC->NAME |= MASK} 00012 #define DISABLE_EMAC_BIT(NAME, MASK)(LPC_EMAC->NAME = LPC_EMAC->NAME & ~MASK} 00013 00014 using namespace LPC1769Reg; 00015 00016 uint8_t LPC1769Emac::mac_[6]; 00017 00018 Descriptor LPC1769Emac::rx_desc_[LPC1769Emac::N_RX_BUF] BUFFER_SECTION; 00019 Descriptor LPC1769Emac::tx_desc_[LPC1769Emac::N_TX_BUF] BUFFER_SECTION; 00020 StatusRx LPC1769Emac::rx_status_[LPC1769Emac::N_RX_BUF] BUFFER_SECTION; 00021 StatusTx LPC1769Emac::tx_status_[LPC1769Emac::N_TX_BUF] BUFFER_SECTION; 00022 Frame LPC1769Emac::rx_frame_[LPC1769Emac::N_RX_BUF] BUFFER_SECTION; 00023 Frame LPC1769Emac::tx_frame_[LPC1769Emac::N_TX_BUF] BUFFER_SECTION; 00024 00025 // === inline debug function 00026 #if 0 00027 #include "global.h" 00028 static inline void print_buffer(const char* title, uint8_t *buf, uint16_t size) { 00029 serial.printf("%s (%d bytes) dst:%02x %02x %02x %02x %02x %02x ", 00030 title, size, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); 00031 buf += 6; 00032 serial.printf("src:%02x %02x %02x %02x %02x %02x ", 00033 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); 00034 buf += 6; 00035 serial.printf("type:%02x %02x\r\n", buf[0], buf[1]); 00036 } 00037 #endif 00038 00039 // === public functions === 00040 LPC1769Emac::LPC1769Emac() { 00041 // set address 00042 // enable ethernet block 00043 LPC_SC->PCONP |= 0x40000000; 00044 00045 // enable alternate functions for ethernet. 00046 // old values are not saved because those pins have only two functions. 00047 LPC_PINCON->PINSEL2 = 0x50150105; 00048 LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005; 00049 } 00050 00051 LPC1769Emac::~LPC1769Emac() { 00052 // TODO: disable PHY before disable ethernet block? 00053 00054 // disable alternate functions for ethernet 00055 LPC_PINCON->PINSEL2 = 0x00000000; 00056 LPC_PINCON->PINSEL3 = LPC_PINCON->PINSEL3 & ~0x0000000F; 00057 00058 // disable ethernet block 00059 LPC_SC->PCONP = LPC_SC->PCONP & ~0x40000000; 00060 } 00061 00062 bool 00063 LPC1769Emac::PhyWrite(uint8_t reg, uint16_t value) { 00064 LPC_EMAC->MADR = PHY_ADDR | reg; 00065 LPC_EMAC->MWTD = value; 00066 00067 uint32_t i; 00068 for (i = 0; i < 0x10000; i++) { 00069 if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { 00070 return true; 00071 } 00072 } 00073 return false; 00074 } 00075 00076 uint16_t 00077 LPC1769Emac::PhyRead(uint8_t reg) { 00078 LPC_EMAC->MADR = PHY_ADDR | reg; 00079 LPC_EMAC->MCMD = MCMD_READ; 00080 00081 uint32_t i; 00082 for (i = 0; i < 0x10000; i++) { 00083 if ((LPC_EMAC->MIND & MIND_BUSY) == 0) { 00084 break; 00085 } 00086 } 00087 LPC_EMAC->MCMD = 0x0000; 00088 00089 return LPC_EMAC->MRDD; 00090 } 00091 00092 void 00093 LPC1769Emac::SetAddress(uint8_t a5, uint8_t a4, uint8_t a3, uint8_t a2, uint8_t a1, uint8_t a0) { 00094 mac_[5] = a0; 00095 mac_[4] = a1; 00096 mac_[3] = a2; 00097 mac_[2] = a3; 00098 mac_[1] = a4; 00099 mac_[0] = a5; 00100 } 00101 00102 void 00103 LPC1769Emac::UpdateAddress(uint8_t a5, uint8_t a4, uint8_t a3, uint8_t a2, uint8_t a1, uint8_t a0) { 00104 mac_[5] = a0; 00105 mac_[4] = a1; 00106 mac_[3] = a2; 00107 mac_[2] = a3; 00108 mac_[1] = a4; 00109 mac_[0] = a5; 00110 WriteAddress_(); 00111 } 00112 00113 void 00114 LPC1769Emac::StartRx() { 00115 LPC_EMAC->Command |= CMD_RX_EN; 00116 LPC_EMAC->MAC1 |= MAC1_RX_EN; 00117 //LPC_EMAC->IntEnable |= INT_RX_DONE; 00118 } 00119 00120 void 00121 LPC1769Emac::StartTx() { 00122 LPC_EMAC->Command |= CMD_TX_EN; 00123 //LPC_EMAC->IntEnable |= INT_TX_DONE; 00124 } 00125 00126 void 00127 LPC1769Emac::StopRx() { 00128 LPC_EMAC->Command = LPC_EMAC->Command & ~CMD_RX_EN; 00129 LPC_EMAC->MAC1 &= ~MAC1_RX_EN; 00130 //LPC_EMAC->IntEnable &= ~INT_RX_DONE; 00131 } 00132 00133 void 00134 LPC1769Emac::StopTx() { 00135 LPC_EMAC->Command = LPC_EMAC->Command & ~CMD_TX_EN; 00136 //LPC_EMAC->IntEnable &= ~INT_TX_DONE; 00137 } 00138 00139 bool 00140 LPC1769Emac::Link() { 00141 return ((PhyRead(SMIReg::BasicStatus) & SMIReg::BS_LINK) > 0); 00142 } 00143 00144 uint16_t 00145 LPC1769Emac::Read(void *buf, uint16_t max_size) { 00146 uint32_t index = LPC_EMAC->RxConsumeIndex; 00147 if (index == LPC_EMAC->RxProduceIndex || max_size == 0) return 0; 00148 00149 uint16_t packet_size = (rx_status_[index].info & Descriptor::SIZE_MASK) + 1; 00150 uint16_t size = packet_size - read_size_; 00151 if (size > Frame::MAX_FRAME_LEN) size = Frame::MAX_FRAME_LEN; 00152 if (size > max_size) size = max_size; 00153 memcpy(buf, read_next_, size); 00154 00155 read_size_ += size; 00156 if (read_size_ >= packet_size) { 00157 // goto next buffer 00158 index = (index >= LPC_EMAC->RxDescriptorNumber) ? 0 : ++index; 00159 read_size_ = 0; 00160 read_next_ = rx_frame_[index].buffer; 00161 LPC_EMAC->RxConsumeIndex = index; 00162 } else { 00163 read_next_ += size; 00164 } 00165 00166 return size; 00167 } 00168 00169 uint16_t 00170 LPC1769Emac::ReadyToReceive() { 00171 uint32_t index = LPC_EMAC->RxConsumeIndex; 00172 if (index == LPC_EMAC->RxProduceIndex) return 0; 00173 else return (rx_status_[index].info & Descriptor::SIZE_MASK) + 1; 00174 } 00175 00176 uint16_t 00177 LPC1769Emac::Write(void *buf, uint16_t size) { 00178 if (size + write_size_ > Frame::MAX_FRAME_LEN) size = Frame::MAX_FRAME_LEN - write_size_; 00179 if (size == 0) return 0; 00180 uint32_t index = LPC_EMAC->TxProduceIndex; 00181 00182 memcpy(write_next_, buf, size); 00183 write_next_ += size; 00184 write_size_ += size; 00185 tx_desc_[index].control = (tx_desc_[index].control & (~Descriptor::SIZE_MASK)) | (size - 1); 00186 00187 return size; 00188 } 00189 00190 bool 00191 LPC1769Emac::Send() { 00192 if (write_size_ == 0) return true; 00193 uint32_t index = LPC_EMAC->TxProduceIndex; 00194 uint32_t index_next = (index == LPC_EMAC->TxDescriptorNumber) ? 0 : index + 1; 00195 if (index_next == LPC_EMAC->TxConsumeIndex) return false; 00196 00197 tx_desc_[index].control = (tx_desc_[index].control & (~Descriptor::SIZE_MASK)) | (write_size_ - 1); 00198 LPC_EMAC->TxProduceIndex = index_next; 00199 write_next_ = tx_frame_[index_next].buffer; 00200 write_size_ = 0; 00201 00202 return true; 00203 } 00204 00205 bool 00206 LPC1769Emac::Send(void *buf, uint16_t size) { 00207 write_next_ -= write_size_; 00208 write_size_ = 0; 00209 if (!Write(buf, size)) return false; 00210 return Send(); 00211 } 00212 00213 bool 00214 LPC1769Emac::Reset(LinkMode mode) { 00215 bool link_100m = false; 00216 bool duplex_full = false; 00217 switch (mode) { 00218 case HalfDuplex10: 00219 break; 00220 case FullDuplex10: 00221 duplex_full = true; 00222 break; 00223 case HalfDuplex100: 00224 link_100m = true; 00225 break; 00226 case FullDuplex100: 00227 duplex_full = true; 00228 link_100m = true; 00229 break; 00230 case AutoNegotiate: 00231 duplex_full = true; 00232 link_100m = true; 00233 break; 00234 default: 00235 return false; 00236 } 00237 00238 // reset EMAC 00239 LPC_EMAC->MAC1 = MAC1_RESET_MASK; 00240 LPC_EMAC->Command = CMD_RESET_MASK; 00241 wait_us(100); 00242 00243 // emac settings 00244 LPC_EMAC->MCFG = MCFG_RESET_MII | MCFG_CS_DIV52; // reset MII Management 00245 wait_us(200); 00246 LPC_EMAC->MAC1 = 0x0000; 00247 LPC_EMAC->CLRT = CLRT_DEFAULT; 00248 LPC_EMAC->MAXF = Frame::MAX_FRAME_LEN; 00249 LPC_EMAC->IPGR = IPGR_DEFAULT; 00250 LPC_EMAC->MCFG = MCFG_CS_DIV52; 00251 if (duplex_full) { 00252 LPC_EMAC->MAC2 = MAC2_AUTO_PAD | MAC2_FULL_DUPLEX; 00253 LPC_EMAC->IPGT = IPGT_FULL_DUPLEX; 00254 LPC_EMAC->Command = CMD_RMII | CMD_FULL_DUPLEX; 00255 } else { 00256 LPC_EMAC->MAC2 = MAC2_AUTO_PAD; 00257 LPC_EMAC->IPGT = IPGT_HALF_DUPLEX; 00258 LPC_EMAC->Command = CMD_RMII; 00259 } 00260 LPC_EMAC->SUPP = link_100m ? SUPP_100M_MODE : 0x0000; 00261 00262 // reset PHY 00263 // "the reset process will be completed within 0.5s from the setting of this bit" (8710a datasheet) 00264 PhyWrite(SMIReg::BasicControl, SMIReg::BC_RESET); 00265 uint32_t i; 00266 bool success_flag = false; 00267 for (i = 0; i < 500; i++) { 00268 if ((PhyRead(SMIReg::BasicControl) & SMIReg::BC_RESET) == 0) { // reset bit is self-clearing 00269 success_flag = true; 00270 break; 00271 } 00272 wait_ms(1); 00273 } 00274 if (!success_flag) return false; // failed to reset 00275 00276 // why 100M settings fail?? 00277 switch (mode) { 00278 case HalfDuplex10: 00279 PhyWrite(SMIReg::BasicControl, 0x0000); 00280 break; 00281 case FullDuplex10: 00282 PhyWrite(SMIReg::BasicControl, SMIReg::BC_FULL_DUPLEX); 00283 break; 00284 case HalfDuplex100: 00285 PhyWrite(SMIReg::BasicControl, SMIReg::BC_100M); 00286 break; 00287 case FullDuplex100: 00288 PhyWrite(SMIReg::BasicControl, SMIReg::BC_FULL_DUPLEX | SMIReg::BC_100M); 00289 break; 00290 case AutoNegotiate: 00291 PhyWrite(SMIReg::BasicControl, SMIReg::BC_AUTONEG); 00292 // CheckAutoNeg_(); 00293 break; 00294 default: 00295 return false; 00296 } 00297 00298 InitRxBuffer_(); 00299 InitTxBuffer_(); 00300 WriteAddress_(); 00301 00302 00303 LPC_EMAC->IntClear = INT_ALL_MASK; 00304 LPC_EMAC->RxFilterCtrl = RXFC_BCAST | RXFC_PERFECT; 00305 00306 return true; 00307 } 00308 00309 // === private functions === 00310 void 00311 LPC1769Emac::WriteAddress_() { 00312 LPC_EMAC->SA0 = ((uint16_t)mac_[5] << 8) | mac_[4]; 00313 LPC_EMAC->SA1 = ((uint16_t)mac_[3] << 8) | mac_[2]; 00314 LPC_EMAC->SA2 = ((uint16_t)mac_[1] << 8) | mac_[0]; 00315 } 00316 00317 // currently not used 00318 bool 00319 LPC1769Emac::CheckAutoNeg_() { 00320 bool success_flag = false; 00321 uint32_t i, r; 00322 for (i = 0; i < 0x10000; i++) { 00323 r = PhyRead(SMIReg::BasicStatus); 00324 if (r & SMIReg::BS_AUTONEG_COMPLETE) { 00325 success_flag = true; 00326 break; 00327 } 00328 } 00329 if (!success_flag) return false; 00330 00331 r = PhyRead(SMIReg::PHYSpecialControlStatus); 00332 00333 // update regs 00334 bool link_100m = ((r & SMIReg::SP_100M) > 0); 00335 bool duplex_full = ((r & SMIReg::SP_FULL_DUPLEX) > 0); 00336 00337 if (duplex_full) { 00338 LPC_EMAC->MAC2 = MAC2_AUTO_PAD | MAC2_FULL_DUPLEX; 00339 LPC_EMAC->IPGT = IPGT_FULL_DUPLEX; 00340 LPC_EMAC->Command = CMD_RMII | CMD_FULL_DUPLEX; 00341 } else { 00342 LPC_EMAC->MAC2 = MAC2_AUTO_PAD; 00343 LPC_EMAC->IPGT = IPGT_HALF_DUPLEX; 00344 LPC_EMAC->Command = CMD_RMII; 00345 } 00346 LPC_EMAC->SUPP = link_100m ? SUPP_100M_MODE : 0x0000; 00347 00348 return true; 00349 } 00350 00351 void 00352 LPC1769Emac::InitRxBuffer_() { 00353 uint16_t i; 00354 00355 // set initial descriptor 00356 for (i = 0; i < N_RX_BUF; i++) { 00357 rx_desc_[i].packet = (uint32_t)&rx_frame_[i]; 00358 rx_desc_[i].control = 0x80000000 | (Frame::MAX_FRAME_LEN - 1); 00359 } 00360 00361 // emac registers 00362 LPC_EMAC->RxDescriptor = (uint32_t)rx_desc_; 00363 LPC_EMAC->RxStatus = (uint32_t)rx_status_; 00364 LPC_EMAC->RxDescriptorNumber = N_RX_BUF - 1; // this register is minus one encoded 00365 LPC_EMAC->RxConsumeIndex = 0; 00366 read_next_ = rx_frame_[0].buffer; 00367 read_size_ = 0; 00368 } 00369 00370 void 00371 LPC1769Emac::InitTxBuffer_() { 00372 uint16_t i; 00373 00374 // set initial descriptor 00375 for (i = 0; i < N_TX_BUF; i++) { 00376 tx_desc_[i].packet = (uint32_t)&tx_frame_[i]; 00377 tx_desc_[i].control = 0xf4000000 | Frame::MAX_FRAME_LEN; 00378 tx_status_[i].info = 0; 00379 } 00380 00381 // emac registers 00382 LPC_EMAC->TxDescriptor = (uint32_t)tx_desc_; 00383 LPC_EMAC->TxStatus = (uint32_t)tx_status_; 00384 LPC_EMAC->TxDescriptorNumber = N_TX_BUF - 1; // this register is minus one encoded 00385 LPC_EMAC->TxProduceIndex = 0; 00386 write_next_ = tx_frame_[0].buffer; 00387 write_size_ = 0; 00388 }
Generated on Wed Jul 13 2022 03:01:38 by
1.7.2