FreeRTOS+TCP Simple network interfaces STM32F429

yanvasilij wrote on Monday, September 19, 2016:

Hello!

I am trying to create FreeRTOS+tcp simple network interfaces. I created my own NetworkInterface.c with standard peripheral library and run FreeRTOS_IPInit(). Then I tryed ping my board and did’not get ping answer. ETH_IRQHandler occures, all program doesn’t crash.

MCU - STM32F429
compiler - arm-none-eaby-gcc


NetworkInterface.c:

/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkBufferManagement.h"
#include "stm32f4x7_eth.h"
#include "NetworkInterfaceDefs.h"

/* ST includes. */
#include "stm32f4xx.h"   
/**********************************************************************************
*				prototypes
**********************************************************************************/
static void prvEMACHandlerTask( void *pvParameters );
/**********************************************************************************
*				vars
**********************************************************************************/
static TaskHandle_t xEMACTaskHandle = NULL;
/* Ethernet Rx & Tx DMA Descriptors */
extern ETH_DMADESCTypeDef  DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
/* Ethernet Driver Receive buffers  */
extern uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; 
/* Ethernet Driver Transmit buffers */
extern uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; 
/* Global pointer for last received frame infos */
extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos;
/**********************************************************************************
*				static funs
**********************************************************************************/
static void resetPhy (void)
{
	GPIO_InitTypeDef gpioInit;
	unsigned int some;
	gpioInit.GPIO_Mode = GPIO_Mode_OUT;
	gpioInit.GPIO_OType = GPIO_OType_PP;
	gpioInit.GPIO_Pin = GPIO_Pin_12;
	gpioInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
	gpioInit.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOH, &gpioInit);
	GPIO_WriteBit(GPIOH, GPIO_Pin_12, Bit_RESET);
	some=1000000;
	while (some) some--;
	GPIO_WriteBit(GPIOH, GPIO_Pin_12, Bit_SET);
}

static void initEthGpios (void)
{
	GPIO_InitTypeDef gpioInit;
	unsigned int some;

	RCC->AHB1ENR |= 0x00000010; //GPIOE enable clock
	RCC->AHB1ENR |= 0x00000001; //GPIOA enable clock
	RCC->AHB1ENR |= 0x00000002; //GPIOB enable clock
	RCC->AHB1ENR |= 0x00000004; //GPIOC enable clock
	RCC->AHB1ENR |= 0x00000040; //GPIOG enable clock
	RCC->AHB1ENR |= 0x00000080; //GPIOH enable clock
	
	gpioInit.GPIO_Mode = GPIO_Mode_OUT;
	gpioInit.GPIO_OType = GPIO_OType_PP;
	gpioInit.GPIO_Pin = GPIO_Pin_12;
	gpioInit.GPIO_PuPd = GPIO_PuPd_NOPULL;
	gpioInit.GPIO_Speed = GPIO_Low_Speed;
	GPIO_Init(GPIOH, &gpioInit);
	GPIO_WriteBit(GPIOH, GPIO_Pin_12, Bit_RESET);

	some=1000000;
	while (some) some--;
	
	GPIO_WriteBit(GPIOH, GPIO_Pin_12, Bit_SET);

	/* Enable System configuration controller clock */
	RCC->APB2ENR |= (1 << 14);
	/* Reset Ethernet MAC */
	RCC->AHB1RSTR |=  0x02000000;
	SYSCFG->PMC |=  (1 << 23);
	RCC->AHB1RSTR &= ~0x02000000;
	RCC->AHB1ENR |= 0x1E000047;

	/* Configure Port A ethernet pins (PA.1, PA.2, PA.7) */
	GPIOA->MODER   &= ~0x0000C03C;
	GPIOA->MODER   |=  0x00008028;              /* Pins to alternate function */
	GPIOA->OTYPER  &= ~0x00000086;              /* Pins in push-pull mode     */
	GPIOA->OSPEEDR |=  0x0000C03C;              /* Slew rate as 100MHz pin    */
	GPIOA->PUPDR   &= ~0x0000C03C;              /* No pull up, no pull down   */

	GPIOA->AFR[0]  &= ~0xF0000FF0;
	GPIOA->AFR[0]  |=  0xB0000BB0;              /* Pins to AF11 (Ethernet)    */

	/* Configure Port C ethernet pins (PC.1, PC.4, PC.5) */
	GPIOC->MODER   &= ~0x00000F0C;
	GPIOC->MODER   |=  0x00000A08;              /* Pins to alternate function */
	GPIOC->OTYPER  &= ~0x00000032;              /* Pins in push-pull mode     */
	GPIOC->OSPEEDR |=  0x00000F0C;              /* Slew rate as 100MHz pin    */
	GPIOC->PUPDR   &= ~0x00000F0C;              /* No pull up, no pull down   */

	GPIOC->AFR[0]  &= ~0x00FF00F0;
	GPIOC->AFR[0]  |=  0x00BB00B0;              /* Pins to AF11 (Ethernet)    */

	/* Configure Port G ethernet pins (PB.12, PB.13) */
	GPIOB->MODER   &= ~0x0F000000;
	GPIOB->MODER   |=  0x0A000000;              /* Pin to alternate function  */
	GPIOB->OTYPER  &= ~0x00003000;              /* Pin in push-pull mode      */
	GPIOB->OSPEEDR |=  0x0F000000;              /* Slew rate as 100MHz pin    */
	GPIOB->PUPDR   &= ~0x0F000000;              /* No pull up, no pull down   */

	GPIOB->AFR[1]  &= ~0x00FF0000;
	GPIOB->AFR[1]  |=  0x00BB0000;              /* Pin to AF11 (Ethernet)     */

	/* Configure Port B ethernet pins (PB.11) */
	GPIOB->MODER   &= ~0x00C00000;
	GPIOB->MODER   |=  0x00800000;              /* Pins to alternate function */
	GPIOB->OTYPER  &= ~0x00000800;              /* Pins in push-pull mode     */
	GPIOB->OSPEEDR |=  0x00C00000;              /* Slew rate as 100MHz pin    */
	GPIOB->PUPDR   &= ~0x0FF00000;              /* No pull up, no pull down   */

	GPIOB->AFR[1]  &= ~0x0000F000;
	GPIOB->AFR[1]  |=  0x0000B000;              /* Pins to AF11 (Ethernet)    */
}


/**********************************************************************************
*				global
**********************************************************************************/

/**
 * @brief init ehternet controller
 *
 * @return 
 */
BaseType_t xNetworkInterfaceInitialise( void )
{
	ETH_InitTypeDef ETH_InitStructure;
	/* init randov function */
	if( xEMACTaskHandle == NULL )
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
		RCC->AHB1RSTR |=  0x02000000;
		SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII);

		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx | RCC_AHB1Periph_ETH_MAC_Rx | RCC_AHB1Periph_ETH_MAC_PTP, ENABLE);

		initEthGpios();

		ETH_SoftwareReset();
		while (ETH_GetSoftwareResetStatus() == SET);

		ETH_StructInit(&ETH_InitStructure);

		ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
		ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
		ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;
		ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
		ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
		ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
		ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
		ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
		ETH_InitStructure.ETH_ChecksumOffload = ETH_ChecksumOffload_Enable;

		ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame = ETH_DropTCPIPChecksumErrorFrame_Enable; 
		ETH_InitStructure.ETH_ReceiveStoreForward = ETH_ReceiveStoreForward_Enable;         
		ETH_InitStructure.ETH_TransmitStoreForward = ETH_TransmitStoreForward_Enable;     

		ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;       
		ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;   
		ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;
		ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;      
		ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;                
		ETH_InitStructure.ETH_RxDMABurstLength = ETH_RxDMABurstLength_32Beat;          
		ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;
		ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;

		/* Configure Ethernet */
		ETH_Init(&ETH_InitStructure, PHYAddress);
		//Eth_Link_PHYITConfig(0x01);

		uint8_t macAdr[] = {0x1E, 0x30, 0x6C, 0xA2, 0x45, 0x5C};
		ETH_MACAddressConfig(ETH_MAC_Address0, macAdr);

		ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
		ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
		for(uint32_t i=0; i<ETH_TXBUFNB; i++)
		{
			ETH_DMATxDescChecksumInsertionConfig(&DMATxDscrTab[i], ETH_DMATxDesc_ChecksumTCPUDPICMPFull);
		}
		ETH_FlushTransmitFIFO();
		ETH_DMATransmissionCmd(ENABLE);
		ETH_DMAReceptionCmd(ENABLE);
		ETH_MACTransmissionCmd(ENABLE);
		ETH_MACReceptionCmd(ENABLE);
		/* Reset all interrupts */
		ETH->DMASR  = 0xFFFFFFFF;

		//ETH_DMA_IT_AIS | ETH_DMA_IT_RBU |
		ETH_DMAITConfig(ETH_DMA_IT_NIS |  ETH_DMA_IT_R, ENABLE);

		NVIC_InitTypeDef NVIC_InitStructure;
		NVIC_InitStructure.NVIC_IRQChannel = ETH_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0C;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0C;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);

		ETH_Start();

		xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL,
			   	configMAX_PRIORITIES - 1, &xEMACTaskHandle );
	}
	return pdPASS;
}

/**
 * @brief output data processing
 *
 * @param pxDescriptor
 * @param bReleaseAfterSend
 *
 * @return 
 */
BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxDescriptor,
	   	BaseType_t bReleaseAfterSend )
{
	u32 ulTransmitSize = pxDescriptor->xDataLength;

	if( ulTransmitSize > ETH_MAX_PACKET_SIZE )
	{
		ulTransmitSize = ETH_MAX_PACKET_SIZE;
	}
	/* Copy bytes to dma buffres */
	memcpy( ( void * ) DMATxDscrTab->Buffer1Addr, pxDescriptor->pucEthernetBuffer,
		   	ulTransmitSize );
	/* Prepare transmit descriptors to give to DMA. */
	ETH_Prepare_Transmit_Descriptors(ulTransmitSize);
	iptraceNETWORK_INTERFACE_TRANSMIT();
	if( bReleaseAfterSend != pdFALSE )
	{
		vReleaseNetworkBufferAndDescriptor( pxDescriptor );
	}
	return pdTRUE;
}

/**
 * @brief Ethernet Irq
 */
void ETH_IRQHandler( void )
{
	BaseType_t xHigherPriorityTaskWoken = 0;

	if (ETH_GetDMAITStatus(ETH_DMA_IT_R) != RESET)
	{
		ETH_CheckFrameReceived();
		ETH_DMAClearITPendingBit(ETH_DMA_IT_R);
		vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );
		//portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
	}
	if (ETH_GetDMAITStatus(ETH_DMA_IT_NIS) != RESET)
	{
		ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);
	}
	if (ETH_GetDMAITStatus(ETH_DMA_IT_AIS) != RESET)
	{
		ETH_DMAClearITPendingBit(ETH_DMA_IT_AIS);
	}
	if (ETH_GetDMAITStatus(ETH_DMA_IT_RBU) != RESET)
	{
		ETH_DMAClearITPendingBit(ETH_DMA_IT_RBU);
	}
}

#define BUFFER_SIZE ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING )
#define BUFFER_SIZE_ROUNDED_UP ( ( BUFFER_SIZE + 7 ) & ~0x07UL )
static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ BUFFER_SIZE_ROUNDED_UP ];

/* Static allocation buffers for FreeRTOS+TCP */
void vNetworkInterfaceAllocateRAMToBuffers(
    NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
{
BaseType_t x;

    for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
    {
        pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] );
        *( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) &( pxNetworkBuffers[ x ] );
    }
}

/**
 * @brief ethernet driver handling task
 *
 * @param pvParameters
 */
static void prvEMACHandlerTask( void *pvParameters )
{
	NetworkBufferDescriptor_t *pxBufferDescriptor;
	size_t xBytesReceived;	
	IPStackEvent_t xRxEvent;
	FrameTypeDef frame;
	__IO ETH_DMADESCTypeDef *DMARxNextDesc;

	for( ;; )
	{
		ulTaskNotifyTake( pdFALSE, portMAX_DELAY  );

		while (ETH_CheckFrameReceived())
		{
			frame = ETH_Get_Received_Frame();
			/* Release descriptors to DMA */
			/* Check if frame with multiple DMA buffer segments */
			if (DMA_RX_FRAME_infos->Seg_Count > 1)
			{
				DMARxNextDesc = DMA_RX_FRAME_infos->FS_Rx_Desc;
			}
			else
			{
				DMARxNextDesc = frame.descriptor;
			}

			/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
			for (u32 i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
			{  
				DMARxNextDesc->Status = ETH_DMARxDesc_OWN;
				DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr);
			}

			/* Clear Segment_Count */
			DMA_RX_FRAME_infos->Seg_Count =0;

			/* When Rx Buffer unavailable flag is set: clear it and resume reception */
			if ((ETH->DMASR & ETH_DMASR_RBUS) != (u32)RESET)  
			{
				/* Clear RBUS ETHERNET DMA flag */
				ETH->DMASR = ETH_DMASR_RBUS;
				/* Resume DMA reception */
				ETH->DMARPDR = 0;
			}

			if ( frame.length > 0 )
			{
				 pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( xBytesReceived, 0 );
				 if( pxBufferDescriptor != NULL )
				 {
					 memcpy( pxBufferDescriptor->pucEthernetBuffer,
							 ( uint8_t * ) frame.buffer, frame.length);
					 pxBufferDescriptor->xDataLength = frame.length;
					 if( eConsiderFrameForProcessing( pxBufferDescriptor->pucEthernetBuffer )
							 == eProcessBuffer )
					 {
						 /* The event about to be sent to the TCP/IP is an Rx event. */
						 xRxEvent.eEventType = eNetworkRxEvent;

						 /* pvData is used to point to the network buffer descriptor that
							now references the received data. */
						 xRxEvent.pvData = ( void * ) pxBufferDescriptor;

						 /* Send the data to the TCP/IP stack. */
						 if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
						 {
							 /* The buffer could not be sent to the IP task so the buffer
								must be released. */
							 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );

							 /* Make a call to the standard trace macro to log the
								occurrence. */
							 iptraceETHERNET_RX_EVENT_LOST();
						 }
						 else
						 {
							 /* The message was successfully sent to the TCP/IP stack.
								Call the standard trace macro to log the occurrence. */
							 iptraceNETWORK_INTERFACE_RECEIVE();
						 }
					 }
					 else
					 {
						 /* The Ethernet frame can be dropped, but the Ethernet buffer
							must be released. */
						 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
					 }
				 }
				 else
				 {
					 /* The event was lost because a network buffer was not available.
						Call the standard trace macro to log the occurrence. */
					 iptraceETHERNET_RX_EVENT_LOST();
				 }
			}
		}
	}
}
/**********************************************************************************
*				eof
**********************************************************************************/

Creating freertos+tcp task

/**
 * @file tcpProcess.cpp
 * @brief tcp task and etc.
 * @author 
 * @version 
 * @date 2016-09-16
 */
#include <stdio.h>
/* FreeRTOS includes. */
#include <FreeRTOS.h>
#include "task.h"
#include "timers.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_DHCP.h"
#include "stm32f4xx.h"


const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ] = 
{192, 168, 10, 50};
const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ] = 
{ 255, 255, 255, 0 };
const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ] = 
{192, 168, 10, 1};
const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ] = 
{ 208, 67, 222, 222 };
const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] = 
{ 0x1E, 0x30, 0x6C, 0xA2, 0x45, 0x5C };
/**********************************************************************************
*				static
**********************************************************************************/
static void initRandomFunction (void)
{
	/* Enable RNG clock source */
	RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
	/* RNG Peripheral enable */
	RNG_Cmd(ENABLE);
}
/**********************************************************************************
*				global
**********************************************************************************/
/**
 * @brief random function
 *
 * @return 
 */
UBaseType_t uxRand( void )
{
	const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
	static BaseType_t xInitialised = pdFALSE;
	static UBaseType_t ulNextRand;

	/* Don't initialise until the scheduler is running, as the timeout in the
	random number generator uses the tick count. */
	if( xInitialised == pdFALSE )
	{
			uint32_t ulSeed;
			/* Generate a random number with which to seed the local pseudo random
			   number generating function. */
			while(RNG_GetFlagStatus(RNG_FLAG_DRDY)== RESET);
			ulSeed = RNG_GetRandomNumber();
			ulNextRand = ulSeed;
			xInitialised = pdTRUE;
	}
	/* Utility function to generate a pseudo random number. */
	ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
	return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL );
}

/**
 * @brief start FreeRTOS+TCP
 */
void initTcpProcess (void)
{
	initRandomFunction();
	FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
}

void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
}

void vApplicationPingReplyHook( ePingReplyStatus_t eStatus, uint16_t usIdentifier )
{
}


/**********************************************************************************
*				eof
**********************************************************************************/

rtel wrote on Monday, September 19, 2016:

I’m afraid I cannot spend a lot of time reading through a lot of chip specific code as it would only make sense if I also spend a lot of time reading the hardware manual. We either need more information as to how far you get, or you can use the STM32 driver that is already in the FreeRTOS Labs download.

With regards to how far you get:

  • You say the ETH_IRQHandler() executes. How many times does it execute? What does it do when it executes?

  • Does the task with the handle xEMACTaskHandle execute after being unblocked by the IRQ handler. If so, what does it do?

  • Why do you have the yield that uses xHigherPriorityTaskWoken commented out?

yanvasilij wrote on Monday, September 19, 2016:

Thanks for your answer!

  • The ETH_IRQHandler() happens sometimes without any reason and always when I pinging the board with ping commnad
  • xEMACTaskHandle execute always after ETH_IRQHandler
  • I suppressed xHigherPriorityTaskWoken for save stack. I use cooperative multitasking and switch contex by using vTaskYEILD(). Anyway I can turn it back, but I don’t think that problem in it.

rtel wrote on Monday, September 19, 2016:

I’ve never used the TCP stack with co-operative multi-tasking. I’m not
sure what the result would be.

yanvasilij wrote on Monday, September 19, 2016:

Ok. I turned off co-operative multi-tasking (set configUSE_PREEMPTION to 1 and configIDLE_SHOULD_YIELD to 0). The problem is still exist. Furthermore I figured out that programm crashed to Default_Handler after some time.
Does I understed correct to port FreeRTOS+TCP and build an application (to check ping only) I need:

  • Provide xNetworkInterfaceInitialise() where MAC, PHY and MACDMA are initialized
  • Provide xNetworkInterfaceOutput() for sending data to MAC
  • Send incoming frames to ip stack by xSendEventStructToIPTask()
  • Provide vNetworkInterfaceAllocateRAMToBuffers() to bind staticaly allocated RAM buffres
  • Provide uxRand() to generate random values
  • Provide callbacks like vApplicationIPNetworkEventHook if need
  • Call FreeRTOS_IPInit() with necessary params to run stack

?

rtel wrote on Monday, September 19, 2016:

/ Provide vNetworkInterfaceAllocateRAMToBuffers() to bind staticaly
allocated RAM buffres

That is only necessary if you are using BufferAllocation_1.
BufferAllocation_2 is simpler to use, although slower, and prevents you
allocating buffers from an ISR.

You need to determine which interrupt is calling the default handler in
order to start debugging why you end up there. See the “Determining
Which Exception Handler is Executing” section on the following page:
http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

yanvasilij wrote on Monday, September 19, 2016:

Yes, I use BufferAllocation_1.

I figured out (I used instruction on your link) that HardFault_Handler is occures sometimes (not all time). There is no another tasks in my application except freertos+tcp.

rtel wrote on Monday, September 19, 2016:

Now you know it is a hard fault you need to find where it is occurring.
There is information on that on the same link.

Do you have configASSERT() defined, and stack overflow checking set to 2?

yanvasilij wrote on Monday, September 19, 2016:

I set configASSERT() follows:

#define configASSERT(x) if( ( x ) == 0 ) for(;;)

configCHECK_FOR_STACK_OVERFLOW follow:

#define configCHECK_FOR_STACK_OVERFLOW 2

Declared vApplicationStackOverflowHook:

void vApplicationStackOverflowHook(void)
{
	while(1);
}

So sheduler start succesfully (I’ve never stop in configASSERT() ) and I don’t get vApplicationStackOverflowHook.

When I debug HardFault_Handler I see the follow sequence:

  1. prvPortStartFirstTask() called
  2. prvPortStartFirstTask() called
  3. some strange () 0xfffffffd
  4. HardFault_Handler ()

coidescreen

rtel wrote on Monday, September 19, 2016:

#define configASSERT(x) if( ( x ) == 0 ) for(;:wink:

You also need to disable interrupts - otherwise you would only know if
you hit the assert if it was the highest priority task that was spinning
in the loopl

When I debug HardFault_Handler I see the follow sequence:

  1. prvPortStartFirstTask() called
  2. prvPortStartFirstTask() called
  3. some strange () 0xfffffffd
  4. HardFault_Handler ()

The call stack doesn’t tell you where the fault occurred - to do that
you need to pull the program counter off the stack, as described on the
previously linked page.

yanvasilij wrote on Monday, September 19, 2016:

I did the follows:
In main:

int main(void)
{
	uint32_t *ACTLR = (uint32_t *)0xE000E008;
	*ACTLR |= 2; //setting the DISDEFWBUF bit (bit 1)
...
}

About configASSERT:

extern void vAssertCalled (void);
#define configASSERT(x) if( ( x ) == 0 )  vAssertCalled()
...
//somewhere
void vAssertCalled (void)
{
	taskDISABLE_INTERRUPTS(); 
	for(;;);
}

There is no change. I still have the same debug sequence when HardFault_Handler occurs.

davedoors wrote on Monday, September 19, 2016:

but have your found the instruction that was executing when the hard fault happens?

yanvasilij wrote on Monday, September 19, 2016:

No, I havn’t. As Real Time Engineers ltd. sad call stack doesn’t tell me where the fault occurred. Setting the DISDEFWBUF bit (bit 1) didn’t helped.

rtel wrote on Monday, September 19, 2016:

The page I linked to in my first (or second?) post that you used to find
which handler had been called tells you how to do that though.

yanvasilij wrote on Monday, September 19, 2016:

I am sorry. I was looking in wrong place. So I declared HardFault_Handler as described here. When HardFault_Handler occured I looked into pc varible and figured out that it value is 0x0801a9ea. I looked at 0x0801a9ea in disassembly and figured out that instraction that causes fault is:

			/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
			for (u32 i=0; i<DMA_RX_FRAME_infos->Seg_Count; i++)
			{  
				DMARxNextDesc->Status = ETH_DMARxDesc_OWN; //<< THIS INSTRACTION CAUSES ERROR
				DMARxNextDesc = (ETH_DMADESCTypeDef *)(DMARxNextDesc->Buffer2NextDescAddr);
			}

rtel wrote on Monday, September 19, 2016:

As a guess I would think DMARxNextDesc had an invalid value when you
tried accessing it, so the write to DMARxNextDesc->Status causes a fault.

billskeen68 wrote on Monday, October 03, 2016:

New to debugging FreeRTOS and trying to follow exactly what to change in code to be able to get a precise hard fault PC register address to debug my application. I’ve reviewed this thread, the link from Real Time Engineers and several others, like:

http://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

and

https://blog.frankvh.com/2011/12/07/cortex-m3-m4-hard-fault-handler/

Could someone help out a noob and point me to something specific please? Thanks in advance.

rtel wrote on Tuesday, October 04, 2016:

The link you posted contains source code to do this, so I’m not sure
what other specific information can be provided. Perhaps if you could
show/explain what you have tried and why it didn’t work we could provide
some suggestions.

billskeen68 wrote on Tuesday, October 04, 2016:

I am using the FreeRTOS/Particle/Redbear Duo version of the firmware from:
https://github.com/redbear/firmware

The bug I am trying to find is with my code calling TCPClient.write that is failing randomly.

i = client.write((const uint8_t *)pmessage.c_str(), pmessage.length());

I do a serial print of the up to 900 byte message just before the write and I can see no problems with it. Sometimes it fails immediately after startup, sometimes days or weeks later. When it does fail, I get a HardFault code 1 ( SOS blinks, then 1 blink, repeat).

I have compiled a debug version using Particle/RedBear make files and I have a breakpoint on the prvGetRegistersFromStack function in the core_hal_stm32f2xx.c file. This is the file/function RedBear support told me to put the breakpoint.

When the breakpoint is hit, I examine the pc register and it is pointing to the HardFault_Handler:

Breakpoint 1, HardFault_Handler () at src/stm32f2xx/core_hal_stm32f2xx.c:112
112 __asm volatile
(gdb) info registers
r0 0x0 0
r1 0x0 0
r2 0x2 2
r3 0x20020000 537001984
r4 0x20000dfc 536874492
r5 0x20000dfc 536874492
r6 0x8077da0 134708640
r7 0x20 32
r8 0xa5a5a5a5 -1515870811
r9 0xa5a5a5a5 -1515870811
r10 0xa5a5a5a5 -1515870811
r11 0xa5a5a5a5 -1515870811
r12 0xccccccc 214748364
sp 0x2001ffe0 0x2001ffe0
lr 0xfffffffd -3
pc 0x80533be 0x80533be <HardFault_Handler>
xPSR 0x61000003 1627389955

Not sure what to do from here. That was the reason for the precise hardfault question.

rtel wrote on Tuesday, October 04, 2016:

Have you followed the instructions in the “Handling Imprecise Faults”
section of the page previously linked (setting bit 1 of the ACTLR register)?