Skip to content

Commit 0e78241

Browse files
Working on v1 DMA
1 parent 997ae9c commit 0e78241

File tree

10 files changed

+507
-111
lines changed

10 files changed

+507
-111
lines changed

connectivity/drivers/emac/TARGET_STM/STM32EthMACCommon.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "MbedCRC.h"
2222

2323
// Figure out the Ethernet IP version in use
24-
#ifdef TARGET_STM32H5 || TARGET_STM32H7
24+
#if defined(TARGET_STM32H5) || defined(TARGET_STM32H7)
2525
#define ETH_IP_VERSION_V2
2626
#else
2727
#define ETH_IP_VERSION_V1

connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.cpp

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <mbed_power_mgmt.h>
2121
#include <Timer.h>
2222
#include <mbed_trace.h>
23+
#include "mbed_error.h"
2324

2425
#define TRACE_GROUP "STEMACv1"
2526

@@ -31,7 +32,129 @@ extern "C" void EthDeinitPinmappings();
3132
extern "C" PinName EthGetPhyResetPin();
3233

3334
namespace mbed {
34-
void STM32EthMACv1::MACDriver::ETH_SetMDIOClockRange(ETH_TypeDef * const base) {
35+
void STM32EthMACv1::TxDMA::startDMA() {
36+
// Zero all the Tx descriptors
37+
memset(txDescs.data(), 0, sizeof(stm32_ethv1::TxDescriptor) * TX_NUM_DESCS);
38+
39+
// Set the end-of-ring bit on the last descriptor
40+
txDescs[TX_NUM_DESCS - 1].endOfRing = true;
41+
42+
// Set descriptor list address register
43+
base->DMARDLAR = reinterpret_cast<ptrdiff_t>(&txDescs[0]);
44+
45+
// Start Tx DMA
46+
base->DMAOMR |= ETH_DMAOMR_ST_Msk;
47+
}
48+
49+
void STM32EthMACv1::TxDMA::stopDMA() {
50+
base->DMAOMR &= ~ETH_DMAOMR_ST_Msk;
51+
}
52+
53+
#if __DCACHE_PRESENT
54+
void STM32EthMACv1::TxDMA::cacheInvalidateDescriptor(const size_t descIdx) {
55+
SCB_InvalidateDCache_by_Addr(&txDescs[descIdx], sizeof(stm32_ethv1::TxDescriptor));
56+
}
57+
58+
bool STM32EthMACv1::TxDMA::descOwnedByDMA(size_t descIdx) {
59+
return txDescs[descIdx].dmaOwn;
60+
}
61+
62+
bool STM32EthMACv1::TxDMA::isDMAReadableBuffer(uint8_t const *start, size_t size) const {
63+
#ifdef TARGET_STM32F7
64+
if(reinterpret_cast<ptrdiff_t>(start) < 1024*16) {
65+
// In ITCM memory, not accessible by DMA. Note that ITCM is not included in the CMSIS memory map (yet).
66+
return false;
67+
}
68+
#endif
69+
70+
#if TARGET_STM32F2 || TARGET_STM32F4
71+
// On STM32F2 and F2, ethernet DMA cannot access the flash memory.
72+
if(reinterpret_cast<ptrdiff_t>(start) >= MBED_ROM_START ||
73+
reinterpret_cast<ptrdiff_t>(start + size) <= MBED_ROM_START + MBED_ROM_SIZE)
74+
{
75+
return false;
76+
}
77+
#endif
78+
79+
return true;
80+
}
81+
82+
void STM32EthMACv1::TxDMA::giveToDMA(size_t descIdx, uint8_t const *buffer, size_t len, bool firstDesc, bool lastDesc) {
83+
84+
}
85+
#endif
86+
87+
void STM32EthMACv1::RxDMA::startDMA() {
88+
89+
// Rx buffer size must be a multiple of 4, per the descriptor definition
90+
MBED_ASSERT(rxPoolPayloadSize % sizeof(uint32_t) == 0);
91+
92+
// Zero all the Rx descriptors
93+
memset(rxDescs.data(), 0, sizeof(stm32_ethv1::RxDescriptor) * RX_NUM_DESCS);
94+
95+
// Set the end-of-ring bit on the last descriptor
96+
rxDescs[RX_NUM_DESCS - 1].endOfRing = true;
97+
98+
// Set descriptor list address register
99+
base->DMARDLAR = reinterpret_cast<ptrdiff_t>(&rxDescs[0]);
100+
101+
// Start Rx DMA
102+
base->DMAOMR |= ETH_DMAOMR_SR_Msk;
103+
}
104+
105+
void STM32EthMACv1::RxDMA::stopDMA() {
106+
base->DMAOMR &= ~ETH_DMAOMR_SR_Msk;
107+
}
108+
109+
#if __DCACHE_PRESENT
110+
void STM32EthMACv1::RxDMA::cacheInvalidateDescriptor(const size_t descIdx) {
111+
SCB_InvalidateDCache_by_Addr(&rxDescs[descIdx], sizeof(stm32_ethv1::RxDescriptor));
112+
}
113+
#endif
114+
115+
bool STM32EthMACv1::RxDMA::descOwnedByDMA(const size_t descIdx) {
116+
return rxDescs[descIdx].dmaOwn;
117+
}
118+
119+
bool STM32EthMACv1::RxDMA::isFirstDesc(const size_t descIdx) {
120+
return rxDescs[descIdx].firstDescriptor;
121+
}
122+
123+
bool STM32EthMACv1::RxDMA::isLastDesc(const size_t descIdx) {
124+
return rxDescs[descIdx].lastDescriptor;
125+
}
126+
127+
bool STM32EthMACv1::RxDMA::isErrorDesc(const size_t descIdx) {
128+
return rxDescs[descIdx].errSummary;
129+
}
130+
131+
void STM32EthMACv1::RxDMA::returnDescriptor(const size_t descIdx, uint8_t *buffer)
132+
{
133+
// Configure descriptor
134+
rxDescs[descIdx].buffer1 = buffer;
135+
rxDescs[descIdx].buffer1Size = rxPoolPayloadSize;
136+
rxDescs[descIdx].dmaOwn = true;
137+
138+
// Flush back to main memory
139+
#ifdef __DCACHE_PRESENT
140+
SCB_CleanDCache_by_Addr(&rxDescs[descIdx], sizeof(stm32_ethv1::RxDescriptor));
141+
#else
142+
__DMB(); // Make sure descriptor is written before the below lines
143+
#endif
144+
145+
// Clear buffer unavailable flag (I think this is for information only though)
146+
base->DMASR = ETH_DMASR_RBUS_Msk;
147+
148+
// Demand (good sir!) an Rx descriptor poll
149+
base->DMARPDR = 1;
150+
}
151+
152+
size_t STM32EthMACv1::RxDMA::getTotalLen(const size_t firstDescIdx, const size_t lastDescIdx) {
153+
// Total length of the packet is in the last descriptor
154+
return rxDescs[lastDescIdx].frameLen;
155+
}
156+
157+
void STM32EthMACv1::MACDriver::ETH_SetMDIOClockRange(ETH_TypeDef * const base) {
35158
/* Get the ETHERNET MACMIIAR value */
36159
uint32_t tempreg = base->MACMIIAR;
37160
/* Clear CSR Clock Range CR[2:0] bits */
@@ -61,11 +184,17 @@ namespace mbed {
61184
/* CSR Clock Range between 100-150 MHz */
62185
tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div62;
63186
}
64-
else /* ((hclk >= 150000000)&&(hclk <= 216000000)) */
187+
#ifdef ETH_MACMIIAR_CR_Div102
188+
else if((hclk >= 150000000)&&(hclk <= 216000000))
65189
{
66190
/* CSR Clock Range between 150-216 MHz */
67191
tempreg |= (uint32_t)ETH_MACMIIAR_CR_Div102;
68192
}
193+
#endif
194+
else {
195+
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_ETHERNET, EIO), \
196+
"STM32 EMAC v1: Unsupported HCLK range\n");
197+
}
69198

70199
/* Write to ETHERNET MAC MIIAR: Configure the ETHERNET CSR Clock Range */
71200
base->MACMIIAR = (uint32_t)tempreg;

connectivity/drivers/emac/TARGET_STM/STM32EthMACv1.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#pragma once
1818

1919
#include "CompositeEMAC.h"
20+
#include "STM32EthV1Descriptors.h"
21+
#include "CacheAlignedBuffer.h"
22+
#include "GenericEthDMA.h"
2023

2124
namespace mbed
2225
{
@@ -26,6 +29,62 @@ namespace mbed
2629
*/
2730
class STM32EthMACv1 : public CompositeEMAC
2831
{
32+
class TxDMA : public GenericTxDMALoop
33+
{
34+
protected:
35+
ETH_TypeDef * const base; // Base address of Ethernet peripheral
36+
StaticCacheAlignedBuffer<stm32_ethv1::TxDescriptor, TX_NUM_DESCS> txDescs; // Tx descriptors
37+
38+
void startDMA() override;
39+
40+
void stopDMA() override;
41+
42+
#if __DCACHE_PRESENT
43+
void cacheInvalidateDescriptor(size_t descIdx) override;
44+
#endif
45+
46+
bool descOwnedByDMA(size_t descIdx) override;
47+
48+
bool isDMAReadableBuffer(uint8_t const * start, size_t size) const override;
49+
50+
void giveToDMA(size_t descIdx, uint8_t const * buffer, size_t len, bool firstDesc, bool lastDesc) override;
51+
public:
52+
explicit TxDMA(ETH_TypeDef * const base):
53+
base(base)
54+
{}
55+
};
56+
57+
class RxDMA : public GenericRxDMALoop {
58+
protected:
59+
ETH_TypeDef * const base; // Base address of Ethernet peripheral
60+
StaticCacheAlignedBuffer<stm32_ethv1::RxDescriptor, RX_NUM_DESCS> rxDescs; // Rx descriptors
61+
62+
void startDMA() override;
63+
64+
void stopDMA() override;
65+
66+
#if __DCACHE_PRESENT
67+
void cacheInvalidateDescriptor(size_t descIdx) override;
68+
#endif
69+
70+
bool descOwnedByDMA(size_t descIdx) override;
71+
72+
bool isFirstDesc(size_t descIdx) override;
73+
74+
bool isLastDesc(size_t descIdx) override;
75+
76+
bool isErrorDesc(size_t descIdx) override;
77+
78+
void returnDescriptor(size_t descIdx, uint8_t * buffer) override;
79+
80+
size_t getTotalLen(size_t firstDescIdx, size_t lastDescIdx) override;
81+
82+
public:
83+
explicit RxDMA(ETH_TypeDef * const base):
84+
base(base)
85+
{}
86+
};
87+
2988
class MACDriver : public CompositeEMAC::MACDriver {
3089
ETH_TypeDef * const base; // Base address of Ethernet peripheral
3190

connectivity/drivers/emac/TARGET_STM/STM32EthMACv2.cpp

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,48 @@ namespace mbed {
5050
base->DMACTCR &= ~ETH_DMACTCR_ST;
5151
}
5252

53+
#if __DCACHE_PRESENT
54+
void STM32EthMACv2::TxDMA::cacheInvalidateDescriptor(size_t descIdx) {
55+
SCB_InvalidateDCache_by_Addr(&txDescs[descIdx], sizeof(stm32_ethv2::EthTxDescriptor));
56+
}
57+
#endif
58+
59+
bool STM32EthMACv2::TxDMA::descOwnedByDMA(size_t descIdx) {
60+
return txDescs[descIdx].formats.fromDMA.dmaOwn;
61+
}
62+
5363
bool STM32EthMACv2::TxDMA::isDMAReadableBuffer(uint8_t const *start, const size_t size) const
5464
{
65+
#ifdef TARGET_STM32H7
5566
// On STM32H7, the Ethernet DMA cannot access data in DTCM. So, if someone sends
5667
// a packet with a data pointer in DTCM (e.g. a stack allocated payload), everything
5768
// will break if we don't copy it first.
58-
#ifdef MBED_RAM_BANK_SRAM_DTC_START
59-
if(reinterpret_cast<ptrdiff_t>(start) >= MBED_RAM_BANK_SRAM_DTC_START &&
69+
if(reinterpret_cast<ptrdiff_t>(start) >= MBED_RAM_BANK_SRAM_DTC_START ||
6070
reinterpret_cast<ptrdiff_t>(start + size) <= MBED_RAM_BANK_SRAM_DTC_START + MBED_RAM_BANK_SRAM_DTC_SIZE)
6171
{
6272
return false;
6373
}
6474
#endif
75+
76+
#ifdef TARGET_STM32H5
77+
// On STM32H7, the Ethernet DMA cannot access data in backup SRAM.
78+
if(reinterpret_cast<ptrdiff_t>(start) >= MBED_RAM_BANK_SRAM_BKUP_START ||
79+
reinterpret_cast<ptrdiff_t>(start + size) <= MBED_RAM_BANK_SRAM_BKUP_START + MBED_RAM_BANK_SRAM_BKUP_SIZE)
80+
{
81+
return false;
82+
}
83+
#endif
84+
6585
return true;
6686
}
6787

68-
void STM32EthMACv2::TxDMA::giveToDMA(const size_t descIdx, const bool firstDesc, const bool lastDesc) {
88+
void STM32EthMACv2::TxDMA::giveToDMA(const size_t descIdx, uint8_t const * const buffer, const size_t len, const bool firstDesc, const bool lastDesc) {
6989
auto & desc = txDescs[descIdx];
7090

91+
// Set buffer
92+
desc.formats.toDMA.buffer1Addr = buffer;
93+
desc.formats.toDMA.buffer1Len = len;
94+
7195
// Note that we have to configure these every time as
7296
// they get wiped away when the DMA gives back the descriptor
7397
desc.formats.toDMA._reserved = 0;
@@ -84,9 +108,11 @@ namespace mbed {
84108
desc.formats.toDMA.timestampEnable = false;
85109
desc.formats.toDMA.dmaOwn = true;
86110

87-
#if __DCACHE_PRESENT
88111
// Write descriptor back to main memory
112+
#if __DCACHE_PRESENT
89113
SCB_CleanDCache_by_Addr(&desc, sizeof(stm32_ethv2::EthTxDescriptor));
114+
#else
115+
__DMB(); // Make sure descriptor is written before the below lines
90116
#endif
91117

92118
// Move tail pointer register to point to the descriptor after this descriptor.
@@ -119,6 +145,30 @@ namespace mbed {
119145
base->DMACTCR &= ~ETH_DMACRCR_SR;
120146
}
121147

148+
#if __DCACHE_PRESENT
149+
void STM32EthMACv2::RxDMA::cacheInvalidateDescriptor(size_t descIdx) {
150+
SCB_InvalidateDCache_by_Addr(&rxDescs[descIdx], sizeof(stm32_ethv2::EthRxDescriptor));
151+
}
152+
#endif
153+
154+
bool STM32EthMACv2::RxDMA::descOwnedByDMA(size_t descIdx) {
155+
return rxDescs[descIdx].formats.toDMA.dmaOwn;
156+
}
157+
158+
bool STM32EthMACv2::RxDMA::isFirstDesc(size_t descIdx) {
159+
return rxDescs[descIdx].formats.fromDMA.firstDescriptor;
160+
}
161+
162+
bool STM32EthMACv2::RxDMA::isLastDesc(size_t descIdx) {
163+
return rxDescs[descIdx].formats.fromDMA.lastDescriptor;
164+
}
165+
166+
bool STM32EthMACv2::RxDMA::isErrorDesc(size_t descIdx) {
167+
// For right now, we treat context descriptors equivalent to error descs.
168+
// Currently we do not use them, so if we did get one, we just want to get rid of it.
169+
return rxDescs[descIdx].formats.fromDMA.errorSummary || rxDescs[descIdx].formats.fromDMA.context;
170+
}
171+
122172
void STM32EthMACv2::RxDMA::returnDescriptor(const size_t descIdx, uint8_t * const buffer) {
123173
auto & desc = rxDescs[descIdx];
124174

@@ -136,6 +186,8 @@ namespace mbed {
136186
#if __DCACHE_PRESENT
137187
// Flush to main memory
138188
SCB_CleanDCache_by_Addr(&desc, __SCB_DCACHE_LINE_SIZE);
189+
#else
190+
__DMB(); // Make sure descriptor is written before the below lines
139191
#endif
140192

141193
// Update tail ptr to issue "rx poll demand" and mark this descriptor for receive.

0 commit comments

Comments
 (0)