1 |
582 |
jeremybenn |
/*
|
2 |
|
|
FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
|
3 |
|
|
|
4 |
|
|
***************************************************************************
|
5 |
|
|
* *
|
6 |
|
|
* If you are: *
|
7 |
|
|
* *
|
8 |
|
|
* + New to FreeRTOS, *
|
9 |
|
|
* + Wanting to learn FreeRTOS or multitasking in general quickly *
|
10 |
|
|
* + Looking for basic training, *
|
11 |
|
|
* + Wanting to improve your FreeRTOS skills and productivity *
|
12 |
|
|
* *
|
13 |
|
|
* then take a look at the FreeRTOS books - available as PDF or paperback *
|
14 |
|
|
* *
|
15 |
|
|
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" *
|
16 |
|
|
* http://www.FreeRTOS.org/Documentation *
|
17 |
|
|
* *
|
18 |
|
|
* A pdf reference manual is also available. Both are usually delivered *
|
19 |
|
|
* to your inbox within 20 minutes to two hours when purchased between 8am *
|
20 |
|
|
* and 8pm GMT (although please allow up to 24 hours in case of *
|
21 |
|
|
* exceptional circumstances). Thank you for your support! *
|
22 |
|
|
* *
|
23 |
|
|
***************************************************************************
|
24 |
|
|
|
25 |
|
|
This file is part of the FreeRTOS distribution.
|
26 |
|
|
|
27 |
|
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
28 |
|
|
the terms of the GNU General Public License (version 2) as published by the
|
29 |
|
|
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
30 |
|
|
***NOTE*** The exception to the GPL is included to allow you to distribute
|
31 |
|
|
a combined work that includes FreeRTOS without being obliged to provide the
|
32 |
|
|
source code for proprietary components outside of the FreeRTOS kernel.
|
33 |
|
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
34 |
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
35 |
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
36 |
|
|
more details. You should have received a copy of the GNU General Public
|
37 |
|
|
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
38 |
|
|
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
39 |
|
|
by writing to Richard Barry, contact details for whom are available on the
|
40 |
|
|
FreeRTOS WEB site.
|
41 |
|
|
|
42 |
|
|
1 tab == 4 spaces!
|
43 |
|
|
|
44 |
|
|
http://www.FreeRTOS.org - Documentation, latest information, license and
|
45 |
|
|
contact details.
|
46 |
|
|
|
47 |
|
|
http://www.SafeRTOS.com - A version that is certified for use in safety
|
48 |
|
|
critical systems.
|
49 |
|
|
|
50 |
|
|
http://www.OpenRTOS.com - Commercial support, development, porting,
|
51 |
|
|
licensing and training services.
|
52 |
|
|
*/
|
53 |
|
|
|
54 |
|
|
/* FreeRTOS includes. */
|
55 |
|
|
#include "FreeRTOS.h"
|
56 |
|
|
#include "semphr.h"
|
57 |
|
|
#include "task.h"
|
58 |
|
|
#include "emac.h"
|
59 |
|
|
|
60 |
|
|
/* Library includes. */
|
61 |
|
|
#include "stm32fxxx_eth.h"
|
62 |
|
|
#include "stm32f10x_gpio.h"
|
63 |
|
|
#include "stm32f10x_rcc.h"
|
64 |
|
|
#include "stm32f10x_nvic.h"
|
65 |
|
|
|
66 |
|
|
/*-----------------------------------------------------------*/
|
67 |
|
|
|
68 |
|
|
/* Hardware specifics. */
|
69 |
|
|
#define uipRCC_MAC_CLOCK ( 1UL << 14UL )
|
70 |
|
|
#define uipRCC_MAC_TX_CLOCK ( 1UL << 15UL )
|
71 |
|
|
#define uipRCC_MAC_RX_CLOCK ( 1UL << 16UL )
|
72 |
|
|
#define uipPHY_ADDRESS ( 1 )
|
73 |
|
|
#define uipENET_IRQ_NUM ( 61 )
|
74 |
|
|
#define uipMODE_MII ( 1UL << 23UL )
|
75 |
|
|
#define uipREMAP_MAC_IO ( 1UL << 21UL )
|
76 |
|
|
|
77 |
|
|
/* The number of descriptors to chain together for use by the Rx DMA. */
|
78 |
|
|
#define uipNUM_RX_DESCRIPTORS 4
|
79 |
|
|
|
80 |
|
|
/* The total number of buffers to be available. At most (?) there should be
|
81 |
|
|
one available for each Rx descriptor, one for current use, and one that is
|
82 |
|
|
in the process of being transmitted. */
|
83 |
|
|
#define uipNUM_BUFFERS ( uipNUM_RX_DESCRIPTORS + 2 )
|
84 |
|
|
|
85 |
|
|
/* Each buffer is sized to fit an entire Ethernet packet. This is for
|
86 |
|
|
simplicity and speed, but could waste RAM. */
|
87 |
|
|
#define uipMAX_PACKET_SIZE 1520
|
88 |
|
|
|
89 |
|
|
/* The field in the descriptor that is unused by this configuration is used to
|
90 |
|
|
hold the send count. This is just #defined to a meaningful name. */
|
91 |
|
|
#define SendCount Buffer2NextDescAddr
|
92 |
|
|
|
93 |
|
|
/* If no buffers are available, then wait this long before looking again.... */
|
94 |
|
|
#define uipBUFFER_WAIT_DELAY ( 3 / portTICK_RATE_MS )
|
95 |
|
|
|
96 |
|
|
/* ...and don't look more than this many times. */
|
97 |
|
|
#define uipBUFFER_WAIT_ATTEMPTS ( 30 )
|
98 |
|
|
|
99 |
|
|
/* Let the DMA know that a new descriptor has been made available to it. */
|
100 |
|
|
#define prvRxDescriptorAvailable() ETH_DMA->DMARPDR = 0
|
101 |
|
|
|
102 |
|
|
/*-----------------------------------------------------------*/
|
103 |
|
|
|
104 |
|
|
/*
|
105 |
|
|
* Configure the IO for Ethernet use.
|
106 |
|
|
*/
|
107 |
|
|
static void prvSetupEthGPIO( void );
|
108 |
|
|
|
109 |
|
|
/*
|
110 |
|
|
* Return a pointer to an unused buffer, marking the returned buffer as now
|
111 |
|
|
* in use.
|
112 |
|
|
*/
|
113 |
|
|
static unsigned char *prvGetNextBuffer( void );
|
114 |
|
|
|
115 |
|
|
/*-----------------------------------------------------------*/
|
116 |
|
|
|
117 |
|
|
/* Allocate the Rx descriptors used by the DMA. */
|
118 |
|
|
static ETH_DMADESCTypeDef xRxDescriptors[ uipNUM_RX_DESCRIPTORS ] __attribute__((aligned(4)));
|
119 |
|
|
|
120 |
|
|
/* Allocate the descriptor used for transmitting. It might be that better
|
121 |
|
|
performance could be achieved by having more than one Tx descriptor, but
|
122 |
|
|
in this simple case only one is used. */
|
123 |
|
|
static volatile ETH_DMADESCTypeDef xTxDescriptor __attribute__((aligned(4)));
|
124 |
|
|
|
125 |
|
|
/* Buffers used for receiving and transmitting data. */
|
126 |
|
|
static unsigned char ucMACBuffers[ uipNUM_BUFFERS ][ uipMAX_PACKET_SIZE ] __attribute__((aligned(4)));
|
127 |
|
|
|
128 |
|
|
/* Each ucBufferInUse index corresponds to a position in the same index in the
|
129 |
|
|
ucMACBuffers array. If the index contains a 1 then the buffer within
|
130 |
|
|
ucMACBuffers is in use, if it contains a 0 then the buffer is free. */
|
131 |
|
|
static unsigned char ucBufferInUse[ uipNUM_BUFFERS ] = { 0 };
|
132 |
|
|
|
133 |
|
|
/* Index to the Rx descriptor to inspect next when looking for a received
|
134 |
|
|
packet. */
|
135 |
|
|
static unsigned long ulNextDescriptor;
|
136 |
|
|
|
137 |
|
|
/* The uip_buffer is not a fixed array, but instead gets pointed to the buffers
|
138 |
|
|
allocated within this file. */
|
139 |
|
|
extern unsigned char * uip_buf;
|
140 |
|
|
|
141 |
|
|
/*-----------------------------------------------------------*/
|
142 |
|
|
|
143 |
|
|
portBASE_TYPE xEthInitialise( void )
|
144 |
|
|
{
|
145 |
|
|
static ETH_InitTypeDef xEthInit; /* Static so as not to take up too much stack space. */
|
146 |
|
|
NVIC_InitTypeDef xNVICInit;
|
147 |
|
|
const unsigned char ucMACAddress[] = { configMAC_ADDR0, configMAC_ADDR1, configMAC_ADDR2, configMAC_ADDR3, configMAC_ADDR4, configMAC_ADDR5 };
|
148 |
|
|
portBASE_TYPE xReturn;
|
149 |
|
|
unsigned long ul;
|
150 |
|
|
|
151 |
|
|
/* Start with things in a safe known state. */
|
152 |
|
|
ETH_DeInit();
|
153 |
|
|
for( ul = 0; ul < uipNUM_RX_DESCRIPTORS; ul++ )
|
154 |
|
|
{
|
155 |
|
|
ETH_DMARxDescReceiveITConfig( &( xRxDescriptors[ ul ] ), DISABLE );
|
156 |
|
|
}
|
157 |
|
|
|
158 |
|
|
/* Route clock to the peripheral. */
|
159 |
|
|
RCC->AHBENR |= ( uipRCC_MAC_CLOCK | uipRCC_MAC_TX_CLOCK | uipRCC_MAC_RX_CLOCK );
|
160 |
|
|
|
161 |
|
|
/* Set the MAC address. */
|
162 |
|
|
ETH_MACAddressConfig( ETH_MAC_Address0, ( unsigned char * ) ucMACAddress );
|
163 |
|
|
|
164 |
|
|
/* Use MII mode. */
|
165 |
|
|
AFIO->MAPR &= ~( uipMODE_MII );
|
166 |
|
|
|
167 |
|
|
/* Configure all the GPIO as required for MAC/PHY interfacing. */
|
168 |
|
|
prvSetupEthGPIO();
|
169 |
|
|
|
170 |
|
|
/* Reset the peripheral. */
|
171 |
|
|
ETH_SoftwareReset();
|
172 |
|
|
while( ETH_GetSoftwareResetStatus() == SET );
|
173 |
|
|
|
174 |
|
|
/* Initialise using the whopping big structure. Code space could be saved
|
175 |
|
|
by making this a const struct, however that would mean changes to the
|
176 |
|
|
structure within the library header files could break the code, so for now
|
177 |
|
|
just set everything manually at run time. */
|
178 |
|
|
xEthInit.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;
|
179 |
|
|
xEthInit.ETH_Watchdog = ETH_Watchdog_Disable;
|
180 |
|
|
xEthInit.ETH_Jabber = ETH_Jabber_Disable;
|
181 |
|
|
xEthInit.ETH_JumboFrame = ETH_JumboFrame_Disable;
|
182 |
|
|
xEthInit.ETH_InterFrameGap = ETH_InterFrameGap_96Bit;
|
183 |
|
|
xEthInit.ETH_CarrierSense = ETH_CarrierSense_Enable;
|
184 |
|
|
xEthInit.ETH_Speed = ETH_Speed_10M;
|
185 |
|
|
xEthInit.ETH_ReceiveOwn = ETH_ReceiveOwn_Disable;
|
186 |
|
|
xEthInit.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
|
187 |
|
|
xEthInit.ETH_Mode = ETH_Mode_HalfDuplex;
|
188 |
|
|
xEthInit.ETH_ChecksumOffload = ETH_ChecksumOffload_Disable;
|
189 |
|
|
xEthInit.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
|
190 |
|
|
xEthInit.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
|
191 |
|
|
xEthInit.ETH_BackOffLimit = ETH_BackOffLimit_10;
|
192 |
|
|
xEthInit.ETH_DeferralCheck = ETH_DeferralCheck_Disable;
|
193 |
|
|
xEthInit.ETH_ReceiveAll = ETH_ReceiveAll_Enable;
|
194 |
|
|
xEthInit.ETH_SourceAddrFilter = ETH_SourceAddrFilter_Disable;
|
195 |
|
|
xEthInit.ETH_PassControlFrames = ETH_PassControlFrames_ForwardPassedAddrFilter;
|
196 |
|
|
xEthInit.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Disable;
|
197 |
|
|
xEthInit.ETH_DestinationAddrFilter = ETH_DestinationAddrFilter_Normal;
|
198 |
|
|
xEthInit.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
|
199 |
|
|
xEthInit.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
|
200 |
|
|
xEthInit.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
|
201 |
|
|
xEthInit.ETH_HashTableHigh = 0x0;
|
202 |
|
|
xEthInit.ETH_HashTableLow = 0x0;
|
203 |
|
|
xEthInit.ETH_PauseTime = 0x0;
|
204 |
|
|
xEthInit.ETH_ZeroQuantaPause = ETH_ZeroQuantaPause_Disable;
|
205 |
|
|
xEthInit.ETH_PauseLowThreshold = ETH_PauseLowThreshold_Minus4;
|
206 |
|
|
xEthInit.ETH_UnicastPauseFrameDetect = ETH_UnicastPauseFrameDetect_Disable;
|
207 |
|
|
xEthInit.ETH_ReceiveFlowControl = ETH_ReceiveFlowControl_Disable;
|
208 |
|
|
xEthInit.ETH_TransmitFlowControl = ETH_TransmitFlowControl_Disable;
|
209 |
|
|
xEthInit.ETH_VLANTagComparison = ETH_VLANTagComparison_16Bit;
|
210 |
|
|
xEthInit.ETH_VLANTagIdentifier = 0x0;
|
211 |
|
|
xEthInit.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Disable;
|
212 |
|
|
xEthInit.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;
|
213 |
|
|
xEthInit.ETH_FlushReceivedFrame = ETH_FlushReceivedFrame_Disable;
|
214 |
|
|
xEthInit.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;
|
215 |
|
|
xEthInit.ETH_TransmitThresholdControl = ETH_TransmitThresholdControl_64Bytes;
|
216 |
|
|
xEthInit.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;
|
217 |
|
|
xEthInit.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;
|
218 |
|
|
xEthInit.ETH_ReceiveThresholdControl = ETH_ReceiveThresholdControl_64Bytes;
|
219 |
|
|
xEthInit.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Disable;
|
220 |
|
|
xEthInit.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;
|
221 |
|
|
xEthInit.ETH_FixedBurst = ETH_FixedBurst_Disable;
|
222 |
|
|
xEthInit.ETH_RxDMABurstLength = ETH_RxDMABurstLength_1Beat;
|
223 |
|
|
xEthInit.ETH_TxDMABurstLength = ETH_TxDMABurstLength_1Beat;
|
224 |
|
|
xEthInit.ETH_DescriptorSkipLength = 0x0;
|
225 |
|
|
xEthInit.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_1_1;
|
226 |
|
|
|
227 |
|
|
xReturn = ETH_Init( &xEthInit, uipPHY_ADDRESS );
|
228 |
|
|
|
229 |
|
|
/* Check a link was established. */
|
230 |
|
|
if( xReturn != pdFAIL )
|
231 |
|
|
{
|
232 |
|
|
/* Rx and Tx interrupts are used. */
|
233 |
|
|
ETH_DMAITConfig( ETH_DMA_IT_NIS | ETH_DMA_IT_R | ETH_DMA_IT_T, ENABLE );
|
234 |
|
|
|
235 |
|
|
/* Only a single Tx descriptor is used. For now it is set to use an Rx
|
236 |
|
|
buffer, but will get updated to point to where ever uip_buf is
|
237 |
|
|
pointing prior to its use. */
|
238 |
|
|
ETH_DMATxDescChainInit( ( void * ) &xTxDescriptor, ( void * ) ucMACBuffers, 1 );
|
239 |
|
|
ETH_DMARxDescChainInit( xRxDescriptors, ( void * ) ucMACBuffers, uipNUM_RX_DESCRIPTORS );
|
240 |
|
|
for( ul = 0; ul < uipNUM_RX_DESCRIPTORS; ul++ )
|
241 |
|
|
{
|
242 |
|
|
/* Ensure received data generates an interrupt. */
|
243 |
|
|
ETH_DMARxDescReceiveITConfig( &( xRxDescriptors[ ul ] ), ENABLE );
|
244 |
|
|
|
245 |
|
|
/* Fix up the addresses used by the descriptors.
|
246 |
|
|
The way ETH_DMARxDescChainInit() is not compatible with the buffer
|
247 |
|
|
declarations in this file. */
|
248 |
|
|
xRxDescriptors[ ul ].Buffer1Addr = ( unsigned long ) &( ucMACBuffers[ ul ][ 0 ] );
|
249 |
|
|
|
250 |
|
|
/* Mark the buffer used by this descriptor as in use. */
|
251 |
|
|
ucBufferInUse[ ul ] = pdTRUE;
|
252 |
|
|
}
|
253 |
|
|
|
254 |
|
|
/* When receiving data, start at the first descriptor. */
|
255 |
|
|
ulNextDescriptor = 0;
|
256 |
|
|
|
257 |
|
|
/* Initialise uip_buf to ensure it points somewhere valid. */
|
258 |
|
|
uip_buf = prvGetNextBuffer();
|
259 |
|
|
|
260 |
|
|
/* SendCount must be initialised to 2 to ensure the Tx descriptor looks
|
261 |
|
|
as if its available (as if it has already been sent twice. */
|
262 |
|
|
xTxDescriptor.SendCount = 2;
|
263 |
|
|
|
264 |
|
|
/* Switch on the interrupts in the NVIC. */
|
265 |
|
|
xNVICInit.NVIC_IRQChannel = uipENET_IRQ_NUM;
|
266 |
|
|
xNVICInit.NVIC_IRQChannelPreemptionPriority = configLIBRARY_KERNEL_INTERRUPT_PRIORITY;
|
267 |
|
|
xNVICInit.NVIC_IRQChannelSubPriority = 0;
|
268 |
|
|
xNVICInit.NVIC_IRQChannelCmd = ENABLE;
|
269 |
|
|
NVIC_Init( &xNVICInit );
|
270 |
|
|
|
271 |
|
|
/* Buffers and descriptors are all set up, now enable the MAC. */
|
272 |
|
|
ETH_Start();
|
273 |
|
|
|
274 |
|
|
/* Let the DMA know there are Rx descriptors available. */
|
275 |
|
|
prvRxDescriptorAvailable();
|
276 |
|
|
}
|
277 |
|
|
|
278 |
|
|
return xReturn;
|
279 |
|
|
}
|
280 |
|
|
/*-----------------------------------------------------------*/
|
281 |
|
|
|
282 |
|
|
static unsigned char *prvGetNextBuffer( void )
|
283 |
|
|
{
|
284 |
|
|
portBASE_TYPE x;
|
285 |
|
|
unsigned char *ucReturn = NULL;
|
286 |
|
|
unsigned long ulAttempts = 0;
|
287 |
|
|
|
288 |
|
|
while( ucReturn == NULL )
|
289 |
|
|
{
|
290 |
|
|
/* Look through the buffers to find one that is not in use by
|
291 |
|
|
anything else. */
|
292 |
|
|
for( x = 0; x < uipNUM_BUFFERS; x++ )
|
293 |
|
|
{
|
294 |
|
|
if( ucBufferInUse[ x ] == pdFALSE )
|
295 |
|
|
{
|
296 |
|
|
ucBufferInUse[ x ] = pdTRUE;
|
297 |
|
|
ucReturn = &( ucMACBuffers[ x ][ 0 ] );
|
298 |
|
|
break;
|
299 |
|
|
}
|
300 |
|
|
}
|
301 |
|
|
|
302 |
|
|
/* Was a buffer found? */
|
303 |
|
|
if( ucReturn == NULL )
|
304 |
|
|
{
|
305 |
|
|
ulAttempts++;
|
306 |
|
|
|
307 |
|
|
if( ulAttempts >= uipBUFFER_WAIT_ATTEMPTS )
|
308 |
|
|
{
|
309 |
|
|
break;
|
310 |
|
|
}
|
311 |
|
|
|
312 |
|
|
/* Wait then look again. */
|
313 |
|
|
vTaskDelay( uipBUFFER_WAIT_DELAY );
|
314 |
|
|
}
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
return ucReturn;
|
318 |
|
|
}
|
319 |
|
|
/*-----------------------------------------------------------*/
|
320 |
|
|
|
321 |
|
|
unsigned short usGetMACRxData( void )
|
322 |
|
|
{
|
323 |
|
|
unsigned short usReturn;
|
324 |
|
|
|
325 |
|
|
if( ( xRxDescriptors[ ulNextDescriptor ].Status & ETH_DMARxDesc_ES ) != 0 )
|
326 |
|
|
{
|
327 |
|
|
/* Error in Rx. Discard the frame and give it back to the DMA. */
|
328 |
|
|
xRxDescriptors[ ulNextDescriptor ].Status = ETH_DMARxDesc_OWN;
|
329 |
|
|
prvRxDescriptorAvailable();
|
330 |
|
|
|
331 |
|
|
/* No data to return. */
|
332 |
|
|
usReturn = 0UL;
|
333 |
|
|
|
334 |
|
|
/* Start from the next descriptor the next time this function is called. */
|
335 |
|
|
ulNextDescriptor++;
|
336 |
|
|
if( ulNextDescriptor >= uipNUM_RX_DESCRIPTORS )
|
337 |
|
|
{
|
338 |
|
|
ulNextDescriptor = 0UL;
|
339 |
|
|
}
|
340 |
|
|
}
|
341 |
|
|
else if( ( xRxDescriptors[ ulNextDescriptor ].Status & ETH_DMARxDesc_OWN ) == 0 )
|
342 |
|
|
{
|
343 |
|
|
/* Mark the current buffer as free as uip_buf is going to be set to
|
344 |
|
|
the buffer that contains the received data. */
|
345 |
|
|
vReturnBuffer( uip_buf );
|
346 |
|
|
|
347 |
|
|
/* Get the received data length from the top 2 bytes of the Status
|
348 |
|
|
word and the data itself. */
|
349 |
|
|
usReturn = ( unsigned short ) ( ( xRxDescriptors[ ulNextDescriptor ].Status & ETH_DMARxDesc_FL ) >> 16UL );
|
350 |
|
|
uip_buf = ( unsigned char * ) ( xRxDescriptors[ ulNextDescriptor ].Buffer1Addr );
|
351 |
|
|
|
352 |
|
|
/* Allocate a new buffer to the descriptor. */
|
353 |
|
|
xRxDescriptors[ ulNextDescriptor ].Buffer1Addr = ( unsigned long ) prvGetNextBuffer();
|
354 |
|
|
|
355 |
|
|
/* Give the descriptor back to the DMA. */
|
356 |
|
|
xRxDescriptors[ ulNextDescriptor ].Status = ETH_DMARxDesc_OWN;
|
357 |
|
|
prvRxDescriptorAvailable();
|
358 |
|
|
|
359 |
|
|
/* Start from the next descriptor the next time this function is called. */
|
360 |
|
|
ulNextDescriptor++;
|
361 |
|
|
if( ulNextDescriptor >= uipNUM_RX_DESCRIPTORS )
|
362 |
|
|
{
|
363 |
|
|
ulNextDescriptor = 0UL;
|
364 |
|
|
}
|
365 |
|
|
}
|
366 |
|
|
else
|
367 |
|
|
{
|
368 |
|
|
/* No received data at all. */
|
369 |
|
|
usReturn = 0UL;
|
370 |
|
|
}
|
371 |
|
|
|
372 |
|
|
return usReturn;
|
373 |
|
|
}
|
374 |
|
|
/*-----------------------------------------------------------*/
|
375 |
|
|
|
376 |
|
|
void vSendMACData( unsigned short usDataLen )
|
377 |
|
|
{
|
378 |
|
|
unsigned long ulAttempts = 0UL;
|
379 |
|
|
|
380 |
|
|
/* Check to see if the Tx descriptor is free. The check against <2 is to
|
381 |
|
|
ensure the buffer has been sent twice and in so doing preventing a race
|
382 |
|
|
condition with the DMA on the ETH_DMATxDesc_OWN bit. */
|
383 |
|
|
while( ( xTxDescriptor.SendCount < 2 ) && ( xTxDescriptor.Status & ETH_DMATxDesc_OWN ) == ETH_DMATxDesc_OWN )
|
384 |
|
|
{
|
385 |
|
|
/* Wait for the Tx descriptor to become available. */
|
386 |
|
|
vTaskDelay( uipBUFFER_WAIT_DELAY );
|
387 |
|
|
|
388 |
|
|
ulAttempts++;
|
389 |
|
|
if( ulAttempts > uipBUFFER_WAIT_ATTEMPTS )
|
390 |
|
|
{
|
391 |
|
|
/* Something has gone wrong as the Tx descriptor is still in use.
|
392 |
|
|
Clear it down manually, the data it was sending will probably be
|
393 |
|
|
lost. */
|
394 |
|
|
xTxDescriptor.Status &= ~ETH_DMATxDesc_OWN;
|
395 |
|
|
vReturnBuffer( ( unsigned char * ) xTxDescriptor.Buffer1Addr );
|
396 |
|
|
break;
|
397 |
|
|
}
|
398 |
|
|
}
|
399 |
|
|
|
400 |
|
|
/* Setup the Tx descriptor for transmission. */
|
401 |
|
|
xTxDescriptor.SendCount = 0;
|
402 |
|
|
xTxDescriptor.Buffer1Addr = ( unsigned long ) uip_buf;
|
403 |
|
|
xTxDescriptor.ControlBufferSize = ( unsigned long ) usDataLen;
|
404 |
|
|
xTxDescriptor.Status = ETH_DMATxDesc_OWN | ETH_DMATxDesc_LS | ETH_DMATxDesc_FS | ETH_DMATxDesc_TER | ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC;
|
405 |
|
|
ETH_DMA->DMASR = ETH_DMASR_TBUS;
|
406 |
|
|
ETH_DMA->DMATPDR = 0;
|
407 |
|
|
|
408 |
|
|
/* uip_buf is being sent by the Tx descriptor. Allocate a new buffer. */
|
409 |
|
|
uip_buf = prvGetNextBuffer();
|
410 |
|
|
}
|
411 |
|
|
/*-----------------------------------------------------------*/
|
412 |
|
|
|
413 |
|
|
static void prvSetupEthGPIO( void )
|
414 |
|
|
{
|
415 |
|
|
GPIO_InitTypeDef xEthInit;
|
416 |
|
|
|
417 |
|
|
/* Remap MAC IO. */
|
418 |
|
|
AFIO->MAPR |= ( uipREMAP_MAC_IO );
|
419 |
|
|
|
420 |
|
|
/* Set PA2, PA8, PB5, PB8, PB11, PB12, PB13, PC1 and PC2 for Ethernet
|
421 |
|
|
interfacing. */
|
422 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_2;/* | GPIO_Pin_8; This should be set when the 25MHz is generated by MCO. */
|
423 |
|
|
xEthInit.GPIO_Speed = GPIO_Speed_50MHz;
|
424 |
|
|
xEthInit.GPIO_Mode = GPIO_Mode_AF_PP;
|
425 |
|
|
GPIO_Init( GPIOA, &xEthInit );
|
426 |
|
|
|
427 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_8 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13; /*5*/
|
428 |
|
|
GPIO_Init( GPIOB, &xEthInit );
|
429 |
|
|
|
430 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
|
431 |
|
|
GPIO_Init( GPIOC, &xEthInit );
|
432 |
|
|
|
433 |
|
|
|
434 |
|
|
/* Configure PA0, PA1, PA3, PB10, PC3, PD8, PD9, PD10, PD11 and PD12 as
|
435 |
|
|
inputs. */
|
436 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_3;
|
437 |
|
|
xEthInit.GPIO_Mode = GPIO_Mode_IN_FLOATING;
|
438 |
|
|
GPIO_Init( GPIOA, &xEthInit );
|
439 |
|
|
|
440 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_10;
|
441 |
|
|
GPIO_Init( GPIOB, &xEthInit );
|
442 |
|
|
|
443 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_3;
|
444 |
|
|
GPIO_Init( GPIOC, &xEthInit );
|
445 |
|
|
|
446 |
|
|
xEthInit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
|
447 |
|
|
GPIO_Init( GPIOD, &xEthInit );
|
448 |
|
|
}
|
449 |
|
|
/*-----------------------------------------------------------*/
|
450 |
|
|
|
451 |
|
|
void vReturnBuffer( unsigned char *pucBuffer )
|
452 |
|
|
{
|
453 |
|
|
unsigned long ul;
|
454 |
|
|
|
455 |
|
|
/* Mark a buffer as free for use. */
|
456 |
|
|
for( ul = 0; ul < uipNUM_BUFFERS; ul++ )
|
457 |
|
|
{
|
458 |
|
|
if( ucMACBuffers[ ul ] == pucBuffer )
|
459 |
|
|
{
|
460 |
|
|
ucBufferInUse[ ul ] = pdFALSE;
|
461 |
|
|
break;
|
462 |
|
|
}
|
463 |
|
|
}
|
464 |
|
|
}
|
465 |
|
|
/*-----------------------------------------------------------*/
|
466 |
|
|
|
467 |
|
|
void vMAC_ISR( void )
|
468 |
|
|
{
|
469 |
|
|
unsigned long ulStatus;
|
470 |
|
|
extern xSemaphoreHandle xEMACSemaphore;
|
471 |
|
|
long xHigherPriorityTaskWoken = pdFALSE;
|
472 |
|
|
|
473 |
|
|
/* What caused the interrupt? */
|
474 |
|
|
ulStatus = ETH_DMA->DMASR;
|
475 |
|
|
|
476 |
|
|
/* Clear everything before leaving. */
|
477 |
|
|
ETH_DMA->DMASR = ulStatus;
|
478 |
|
|
|
479 |
|
|
if( ulStatus & ETH_DMA_IT_R )
|
480 |
|
|
{
|
481 |
|
|
/* Data was received. Ensure the uIP task is not blocked as data has
|
482 |
|
|
arrived. */
|
483 |
|
|
xSemaphoreGiveFromISR( xEMACSemaphore, &xHigherPriorityTaskWoken );
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
if( ulStatus & ETH_DMA_IT_T )
|
487 |
|
|
{
|
488 |
|
|
/* Data was transmitted. */
|
489 |
|
|
if( xTxDescriptor.SendCount == 0 )
|
490 |
|
|
{
|
491 |
|
|
/* Send again! */
|
492 |
|
|
( xTxDescriptor.SendCount )++;
|
493 |
|
|
|
494 |
|
|
xTxDescriptor.Status = ETH_DMATxDesc_OWN | ETH_DMATxDesc_LS | ETH_DMATxDesc_FS | ETH_DMATxDesc_TER | ETH_DMATxDesc_TCH | ETH_DMATxDesc_IC;
|
495 |
|
|
ETH_DMA->DMASR = ETH_DMASR_TBUS;
|
496 |
|
|
ETH_DMA->DMATPDR = 0;
|
497 |
|
|
}
|
498 |
|
|
else
|
499 |
|
|
{
|
500 |
|
|
/* The Tx buffer is no longer required. */
|
501 |
|
|
vReturnBuffer( ( unsigned char * ) xTxDescriptor.Buffer1Addr );
|
502 |
|
|
}
|
503 |
|
|
}
|
504 |
|
|
|
505 |
|
|
/* If xSemaphoreGiveFromISR() unblocked a task, and the unblocked task has
|
506 |
|
|
a higher priority than the currently executing task, then
|
507 |
|
|
xHigherPriorityTaskWoken will have been set to pdTRUE and this ISR should
|
508 |
|
|
return directly to the higher priority unblocked task. */
|
509 |
|
|
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
510 |
|
|
}
|
511 |
|
|
|