ShineLAN-X: Growatt-Präfix aus Ordnername entfernt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
e27a47791a
commit
9b61f9780d
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
Enc28J60NetworkClass.cpp — Bitbang-SPI version for non-hardware-SPI pins
|
||||
Based on UIPEthernet by Norbert Truchsess, GPL V2
|
||||
|
||||
Modification: Hardware SPI replaced with bitbang SPI.
|
||||
Target: STM32F103RBT6 with ENC28J60 on PC6(SCK)/PC7(MISO)/PC8(CS)/PC9(MOSI)
|
||||
*/
|
||||
|
||||
#include "Enc28J60Network.h"
|
||||
#include <Arduino.h>
|
||||
#include "config.h" // ETH_SCK_PIN / ETH_MOSI_PIN / ETH_MISO_PIN
|
||||
// Note: <SPI.h> intentionally NOT included — this version uses bitbang SPI
|
||||
|
||||
extern "C" {
|
||||
#include "enc28j60.h"
|
||||
#include "uip.h"
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Bitbang SPI — SPI Mode 0 (CPOL=0, CPHA=0)
|
||||
// Pin definitions come from project include/config.h via build system
|
||||
// ============================================================
|
||||
#ifndef ETH_SCK_PIN
|
||||
#error "ETH_SCK_PIN not defined — check include/config.h"
|
||||
#endif
|
||||
|
||||
static bool _spi_ready = false;
|
||||
|
||||
static void bitbang_init() {
|
||||
if (_spi_ready) return;
|
||||
pinMode(ETH_SCK_PIN, OUTPUT); digitalWrite(ETH_SCK_PIN, LOW);
|
||||
pinMode(ETH_MOSI_PIN, OUTPUT); digitalWrite(ETH_MOSI_PIN, LOW);
|
||||
pinMode(ETH_MISO_PIN, INPUT);
|
||||
_spi_ready = true;
|
||||
}
|
||||
|
||||
static inline uint8_t bitbang_transfer(uint8_t out) {
|
||||
uint8_t in = 0;
|
||||
for (int8_t i = 7; i >= 0; i--) {
|
||||
digitalWrite(ETH_MOSI_PIN, (out >> i) & 1);
|
||||
digitalWrite(ETH_SCK_PIN, HIGH);
|
||||
in = (in << 1) | digitalRead(ETH_MISO_PIN);
|
||||
digitalWrite(ETH_SCK_PIN, LOW);
|
||||
}
|
||||
return in;
|
||||
}
|
||||
// ============================================================
|
||||
|
||||
// set CS to 0 = active
|
||||
#define CSACTIVE digitalWrite(csPin, LOW)
|
||||
// set CS to 1 = passive
|
||||
#define CSPASSIVE digitalWrite(csPin, HIGH)
|
||||
|
||||
bool Enc28J60Network::spiInitialized = false;
|
||||
uint8_t Enc28J60Network::csPin = SS;
|
||||
uint16_t Enc28J60Network::nextPacketPtr;
|
||||
uint8_t Enc28J60Network::bank = 0xff;
|
||||
|
||||
struct memblock Enc28J60Network::receivePkt;
|
||||
|
||||
void Enc28J60Network::initSPI()
|
||||
{
|
||||
if (spiInitialized)
|
||||
return;
|
||||
bitbang_init();
|
||||
pinMode(csPin, OUTPUT);
|
||||
CSPASSIVE;
|
||||
spiInitialized = true;
|
||||
}
|
||||
|
||||
bool Enc28J60Network::init(uint8_t* macaddr)
|
||||
{
|
||||
MemoryPool::init();
|
||||
initSPI();
|
||||
|
||||
// perform system reset
|
||||
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
delay(50);
|
||||
nextPacketPtr = RXSTART_INIT;
|
||||
writeRegPair(ERXSTL, RXSTART_INIT);
|
||||
writeRegPair(ERXRDPTL, RXSTART_INIT);
|
||||
writeRegPair(ERXNDL, RXSTOP_INIT);
|
||||
writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN);
|
||||
writeRegPair(EPMM0, 0x303f);
|
||||
writeRegPair(EPMCSL, 0xf7f9);
|
||||
writeRegPair(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
|
||||
writeRegPair(MAIPGL, 0x0C12);
|
||||
writeReg(MABBIPG, 0x12);
|
||||
writeRegPair(MAMXFLL, MAX_FRAMELEN);
|
||||
writeReg(MAADR5, macaddr[0]);
|
||||
writeReg(MAADR4, macaddr[1]);
|
||||
writeReg(MAADR3, macaddr[2]);
|
||||
writeReg(MAADR2, macaddr[3]);
|
||||
writeReg(MAADR1, macaddr[4]);
|
||||
writeReg(MAADR0, macaddr[5]);
|
||||
phyWrite(PHCON2, PHCON2_HDLDIS);
|
||||
setBank(ECON1);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
phyWrite(PHLCON, 0x476);
|
||||
|
||||
return getrev();
|
||||
}
|
||||
|
||||
memhandle Enc28J60Network::receivePacket()
|
||||
{
|
||||
uint8_t rxstat;
|
||||
uint16_t len;
|
||||
|
||||
if (readReg(EPKTCNT) != 0)
|
||||
{
|
||||
uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ?
|
||||
nextPacketPtr+6-((RXSTOP_INIT + 1)-RXSTART_INIT) : nextPacketPtr+6;
|
||||
writeRegPair(ERDPTL, nextPacketPtr);
|
||||
nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0);
|
||||
nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
|
||||
len = readOp(ENC28J60_READ_BUF_MEM, 0);
|
||||
len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8;
|
||||
len -= 4;
|
||||
rxstat = readOp(ENC28J60_READ_BUF_MEM, 0);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
|
||||
if ((rxstat & 0x80) != 0)
|
||||
{
|
||||
receivePkt.begin = readPtr;
|
||||
receivePkt.size = len;
|
||||
return UIP_RECEIVEBUFFERHANDLE;
|
||||
}
|
||||
setERXRDPT();
|
||||
}
|
||||
return (NOBLOCK);
|
||||
}
|
||||
|
||||
void Enc28J60Network::setERXRDPT()
|
||||
{
|
||||
writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr-1);
|
||||
}
|
||||
|
||||
memaddress Enc28J60Network::blockSize(memhandle handle)
|
||||
{
|
||||
return handle == NOBLOCK ? 0 :
|
||||
handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size;
|
||||
}
|
||||
|
||||
bool Enc28J60Network::sendPacket(memhandle handle)
|
||||
{
|
||||
memblock *packet = &blocks[handle];
|
||||
uint16_t start = packet->begin;
|
||||
uint16_t end = start + packet->size - 1 - UIP_SENDBUFFER_PADDING;
|
||||
|
||||
writeByte(start, 0);
|
||||
|
||||
writeRegPair(ETXSTL, start);
|
||||
writeRegPair(ETXNDL, end);
|
||||
|
||||
bool success = false;
|
||||
for (uint8_t retry = 0; retry < TX_COLLISION_RETRY_COUNT; retry++)
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, EIR, EIR_TXERIF | EIR_TXIF);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
|
||||
uint8_t eir;
|
||||
while (((eir = readReg(EIR)) & (EIR_TXIF | EIR_TXERIF)) == 0);
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS);
|
||||
success = ((eir & EIR_TXERIF) == 0);
|
||||
if (success) break;
|
||||
uint8_t tsv4 = readByte(end + 4);
|
||||
if (!(tsv4 & 0b00100000)) break;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
uint16_t Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len)
|
||||
{
|
||||
memblock *packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle];
|
||||
memaddress start = handle == UIP_RECEIVEBUFFERHANDLE &&
|
||||
packet->begin + position > RXSTOP_INIT ?
|
||||
packet->begin + position-((RXSTOP_INIT + 1)-RXSTART_INIT) :
|
||||
packet->begin + position;
|
||||
writeRegPair(ERDPTL, start);
|
||||
if (len > packet->size - position) len = packet->size - position;
|
||||
return len;
|
||||
}
|
||||
|
||||
uint16_t Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len)
|
||||
{
|
||||
len = setReadPtr(handle, position, len);
|
||||
readBuffer(len, buffer);
|
||||
return len;
|
||||
}
|
||||
|
||||
uint16_t Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len)
|
||||
{
|
||||
memblock *packet = &blocks[handle];
|
||||
uint16_t start = packet->begin + position;
|
||||
if (len > packet->size - position) len = packet->size - position;
|
||||
if (len == 0) return 0;
|
||||
writeRegPair(EWRPTL, start);
|
||||
writeBuffer(len, buffer);
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t Enc28J60Network::readByte(uint16_t addr)
|
||||
{
|
||||
writeRegPair(ERDPTL, addr);
|
||||
CSACTIVE;
|
||||
bitbang_transfer(ENC28J60_READ_BUF_MEM);
|
||||
uint8_t c = bitbang_transfer(0x00);
|
||||
CSPASSIVE;
|
||||
return c;
|
||||
}
|
||||
|
||||
void Enc28J60Network::writeByte(uint16_t addr, uint8_t data)
|
||||
{
|
||||
writeRegPair(EWRPTL, addr);
|
||||
CSACTIVE;
|
||||
bitbang_transfer(ENC28J60_WRITE_BUF_MEM);
|
||||
bitbang_transfer(data);
|
||||
CSPASSIVE;
|
||||
}
|
||||
|
||||
void Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len)
|
||||
{
|
||||
memblock *dest = &blocks[dest_pkt];
|
||||
memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt];
|
||||
memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && src->begin + src_pos > RXSTOP_INIT ?
|
||||
src->begin + src_pos - ((RXSTOP_INIT + 1) - RXSTART_INIT) : src->begin + src_pos;
|
||||
enc28J60_mempool_block_move_callback(dest->begin + dest_pos, start, len);
|
||||
}
|
||||
|
||||
void enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len)
|
||||
{
|
||||
if (len == 1)
|
||||
{
|
||||
Enc28J60Network::writeByte(dest, Enc28J60Network::readByte(src));
|
||||
}
|
||||
else
|
||||
{
|
||||
len += src - 1;
|
||||
Enc28J60Network::writeRegPair(EDMASTL, src);
|
||||
Enc28J60Network::writeRegPair(EDMADSTL, dest);
|
||||
if ((src <= RXSTOP_INIT) && (len > RXSTOP_INIT))
|
||||
len -= ((RXSTOP_INIT + 1)-RXSTART_INIT);
|
||||
Enc28J60Network::writeRegPair(EDMANDL, len);
|
||||
Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN);
|
||||
Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST);
|
||||
while (Enc28J60Network::readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
|
||||
}
|
||||
}
|
||||
|
||||
void Enc28J60Network::freePacket()
|
||||
{
|
||||
setERXRDPT();
|
||||
}
|
||||
|
||||
uint8_t Enc28J60Network::readOp(uint8_t op, uint8_t address)
|
||||
{
|
||||
CSACTIVE;
|
||||
bitbang_transfer(op | (address & ADDR_MASK));
|
||||
if (address & 0x80) bitbang_transfer(0x00); // dummy read for MAC/MII
|
||||
uint8_t c = bitbang_transfer(0x00);
|
||||
CSPASSIVE;
|
||||
return c;
|
||||
}
|
||||
|
||||
void Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data)
|
||||
{
|
||||
CSACTIVE;
|
||||
bitbang_transfer(op | (address & ADDR_MASK));
|
||||
bitbang_transfer(data);
|
||||
CSPASSIVE;
|
||||
}
|
||||
|
||||
void Enc28J60Network::readBuffer(uint16_t len, uint8_t* data)
|
||||
{
|
||||
CSACTIVE;
|
||||
bitbang_transfer(ENC28J60_READ_BUF_MEM);
|
||||
while (len--) *data++ = bitbang_transfer(0x00);
|
||||
CSPASSIVE;
|
||||
}
|
||||
|
||||
void Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data)
|
||||
{
|
||||
CSACTIVE;
|
||||
bitbang_transfer(ENC28J60_WRITE_BUF_MEM);
|
||||
while (len--) bitbang_transfer(*data++);
|
||||
CSPASSIVE;
|
||||
}
|
||||
|
||||
void Enc28J60Network::setBank(uint8_t address)
|
||||
{
|
||||
if ((address & BANK_MASK) != bank)
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0));
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5);
|
||||
bank = (address & BANK_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Enc28J60Network::readReg(uint8_t address)
|
||||
{
|
||||
setBank(address);
|
||||
return readOp(ENC28J60_READ_CTRL_REG, address);
|
||||
}
|
||||
|
||||
void Enc28J60Network::writeReg(uint8_t address, uint8_t data)
|
||||
{
|
||||
setBank(address);
|
||||
writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
|
||||
}
|
||||
|
||||
void Enc28J60Network::writeRegPair(uint8_t address, uint16_t data)
|
||||
{
|
||||
setBank(address);
|
||||
writeOp(ENC28J60_WRITE_CTRL_REG, address, (data & 0xFF));
|
||||
writeOp(ENC28J60_WRITE_CTRL_REG, address+1, (data >> 8));
|
||||
}
|
||||
|
||||
void Enc28J60Network::phyWrite(uint8_t address, uint16_t data)
|
||||
{
|
||||
writeReg(MIREGADR, address);
|
||||
writeRegPair(MIWRL, data);
|
||||
while (readReg(MISTAT) & MISTAT_BUSY) delayMicroseconds(15);
|
||||
}
|
||||
|
||||
uint16_t Enc28J60Network::phyRead(uint8_t address)
|
||||
{
|
||||
writeReg(MIREGADR, address);
|
||||
writeReg(MICMD, MICMD_MIIRD);
|
||||
while (readReg(MISTAT) & MISTAT_BUSY) delayMicroseconds(15);
|
||||
writeReg(MICMD, 0);
|
||||
return (readReg(MIRDL) | readReg(MIRDH) << 8);
|
||||
}
|
||||
|
||||
void Enc28J60Network::clkout(uint8_t clk)
|
||||
{
|
||||
writeReg(ECOCON, clk & 0x7);
|
||||
}
|
||||
|
||||
uint8_t Enc28J60Network::getrev(void)
|
||||
{
|
||||
initSPI();
|
||||
return readReg(EREVID);
|
||||
}
|
||||
|
||||
uint16_t Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len)
|
||||
{
|
||||
uint16_t t;
|
||||
len = setReadPtr(handle, pos, len) - 1;
|
||||
CSACTIVE;
|
||||
bitbang_transfer(ENC28J60_READ_BUF_MEM);
|
||||
uint16_t i;
|
||||
for (i = 0; i < len; i += 2)
|
||||
{
|
||||
t = bitbang_transfer(0x00) << 8;
|
||||
t += bitbang_transfer(0x00);
|
||||
sum += t;
|
||||
if (sum < t) sum++;
|
||||
}
|
||||
if (i == len)
|
||||
{
|
||||
t = (bitbang_transfer(0x00) << 8) + 0;
|
||||
sum += t;
|
||||
if (sum < t) sum++;
|
||||
}
|
||||
CSPASSIVE;
|
||||
return sum;
|
||||
}
|
||||
|
||||
void Enc28J60Network::powerOff()
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
|
||||
delay(50);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
|
||||
delay(50);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
|
||||
}
|
||||
|
||||
void Enc28J60Network::powerOn()
|
||||
{
|
||||
writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
|
||||
delay(50);
|
||||
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
bool Enc28J60Network::linkStatus()
|
||||
{
|
||||
return (phyRead(PHSTAT2) & 0x0400) > 0;
|
||||
}
|
||||
Reference in New Issue
Block a user