1
\$\begingroup\$

I am using code composer studio version 6.1 with TM4C123GH6PM. When dubugging and executing it goes to a function called FaultISR() and then stuck in an infinite loop When trying to see the registers values it display an error message instead of the value of the register:

Error: unable to read

and in the console displays :

CORTEX_M4_0: Trouble Reading Memory Block at 0x400253fc on Page 0 of Length 0x4: Debug Port error occurred.

as the following picture says. all problems and errors

edit

that is my code: It is a led blinking consisting of four files: - DIO.h and DIO.c : which is a driver to the input/output hardware - Reg_Macros.h - blink.c : the app

DIO.h

#ifndef DIO_H_
#define DIO_H_
#include "BasicTypes.h"
/*Values of Port Name*/
#define PA 0
#define PB 1
#define PC 2
#define PD 3
#define PE ox20
#define PF 0x21

/*Pad Current Control*/
#define CRT_2M 0x00
#define CRT_4M 0x01
#define CRT_8M 0x02

/*Pad Input resistance control*/
#define RES_NO 0x00
#define RES_PU 0x01
#define RES_PD 0x02


typedef struct
{
    unsigned int PortName;
    unsigned int PortMask;
    unsigned int PortDirection;
    unsigned int InterRes;
    unsigned int PadCrnt;
}DIO_InitParamtersType;

typedef struct
{
    unsigned int PortName;
    unsigned int PortMask;
    unsigned int PortData;
}DIO_WriteParametersType;

void DIO_Init(DIO_InitParamtersType* InitParamters);
void DIO_Write(DIO_WriteParametersType* WriteParamters);

#endif /* DIO_H_ */

DIO.c

#include "DIO.h"
#include "Reg_Macros.h"
/*Register addresses calculation macros*/
#define REG_ADD_BIT_BANDING(PORT_ID,PORT_MASK,REG_OFFSET)  ((volatile uint32_t *)(((PORT_MASK) << 2) + ((PORT_ID) << 12) + (REG_OFFSET) + (GPIO_APB_REG_ADD_BASE)))
#define REG_ADD(PORT_ID,REG_OFFSET) ((volatile uint32_t *)(((PORT_ID) << 12) + (REG_OFFSET) + (GPIO_APB_REG_ADD_BASE)))


/*Enable Port clock macro*/
#define ENABLE_PORT_CLOCK(PORT_ID) SYSCTL_RCGC2_R |= 1 << (PORT_ID)
/*Write Data Macro*/
#define DIO_WRITE_DATA(PORT_ID,PORT_MASK,PORTD_DATA)  *REG_ADD_BIT_BANDING((PORT_ID),(PORT_MASK),(GPIODATA_REG_OFFSET))= PORTD_DATA

/*Init Direction macro*/
#define DIO_INIT_DIRECTION(PORT_ID,PORT_MASK,PORT_DIRECTION)  *(REG_ADD((PORT_ID),(GPIODIR_REG_OFFSET))) &= ~(PORT_MASK); \
                                                          *(REG_ADD((PORT_ID),(GPIODIR_REG_OFFSET))) |= (PORT_DIRECTION & PORT_MASK)
/*Init Output Current macro*/
#define DIO_INIT_PAD_CRNT(PORT_ID,PORT_MASK,CRT_ID) *REG_ADD((PORT_ID),((GPIOCRT_CTRL_REG_OFFSET) + ((CRT_ID)*4))) |= (PORT_MASK)

/*Init Input Resistor macro*/
#define DIO_INIT_PAD_RES(PORT_ID,PORT_MASK,RES_ID) *REG_ADD((PORT_ID),((GPIORESISTOR_CTRL_REG_OFFSET) + ((RES_ID)*4))) |= (PORT_MASK)


/*Activate and Deactivate Digital Enable macro*/
#define DIO_ACTIVATE_DEGITAL_ENABLE(PORT_ID,PORT_MASK)  *REG_ADD((PORT_ID),(GPIODEN_REG_OFFSET)) |= (PORT_MASK)
#define DIO_DEACTIVATE_DIGITAL_ENABLE(PORT_ID,PORT_MASK)  *REG_ADD((PORT_ID),(GPIODEN_REG_OFFSET)) &= ~(PORT_MASK)

/*Activate and DeAcivate Alternate function*/
#define DIO_ACTIVATE_ALTERNATE_FUNC(PORT_ID,PORT_MASK) *REG_ADD(PORT_ID,GPIOAFSEL_REG_OFFSET) |= PORT_MASK
#define DIO_DEACTIVATE_ALTERNATE_FUNC(PORT_ID,PORT_MASK) *REG_ADD(PORT_ID,GPIOAFSEL_REG_OFFSET) |= *(PORT_MASK)

void DIO_Init(DIO_InitParamtersType* InitParamters)
{
    /*Enable Port Clock*/
    ENABLE_PORT_CLOCK(InitParamters->PortName);

    /*Init PortDirection Direction*/
    DIO_INIT_DIRECTION(InitParamters->PortName,InitParamters->PortMask,InitParamters->PortDirection);

    /*Init Pad Current*/
    DIO_INIT_PAD_CRNT(InitParamters->PortName,InitParamters->PortMask,InitParamters->PadCrnt);

    /*Init Pad Input Resistance*/
    DIO_INIT_PAD_RES(InitParamters->PortName,InitParamters->PortMask,InitParamters->InterRes);

    /*Activate Digital Enable of Port*/
    DIO_ACTIVATE_DEGITAL_ENABLE(InitParamters->PortName,InitParamters->PortMask);

}

void DIO_Write(DIO_WriteParametersType* WriteParamters)
{
    DIO_WRITE_DATA(WriteParamters->PortName,WriteParamters->PortMask,WriteParamters->PortData);
}

Reg_Macros.h

#ifndef REG_MACROS_H_
#define REG_MACROS_H_
#include <stdint.h>

/*System control registers*/
#define SYSCTL_RCGC2_R          (*((volatile unsigned int *)0x400FE108))
/*GPIO APB Regesters address base*/
#define GPIO_APB_REG_ADD_BASE  0x40004000
/*GPIO DIO Registers Offsets*/
#define GPIODATA_REG_OFFSET          0x000
#define GPIODIR_REG_OFFSET           0x400
#define GPIOCRT_CTRL_REG_OFFSET      0x500
#define GPIORESISTOR_CTRL_REG_OFFSET 0x50C
#define GPIODEN_REG_OFFSET           0x51C

#define GPIOAFSEL_REG_OFFSET         0x420
#define GPIOLOCK_REG_OFFSET          0x520
#define GPIOCR_REG_OFFSET            0x524

#endif

blink.c

#include "DIO.h"
void ISRGPIOA(void){
}
int main(void)
{
    DIO_InitParamtersType x;
    DIO_WriteParametersType DataON;
    DIO_WriteParametersType DataOFF;
    x.PortName = PF;
    x.PortDirection = 0xff;
    x.PortMask = 0x0E;
    x.PadCrnt = CRT_2M;
    x.InterRes = RES_NO;
    DataON.PortName = PF;
    DataON.PortMask = 0x02;
    DataON.PortData = 0xff;
    DataOFF.PortName = PF;
    DataOFF.PortMask = 0x02;
    DataOFF.PortData = 0x00;
    unsigned int Delay = 0;
    DIO_Init(&x);

    while(1)
    {
        //LED ON
        DIO_Write(&DataOFF);
        for(Delay = 0 ; Delay < 2000000 ; Delay ++){
        }
        //LED OFF
        DIO_Write(&DataON);
        for(Delay = 0 ; Delay < 2000000 ; Delay ++){
        }
    }
}
\$\endgroup\$
  • \$\begingroup\$ Depending on the code you are running, that debugger behaviour can be completely normal. Do you really want to read those registers, or were you just seeing which registers you could read "at random" while trying to debug your original problem? To help others to help you, I suggest that you explain more about what problem you are trying to debug, and supply an MCVE (Minimum Complete Verified Example) i.e. the smallest complete code example which still shows whatever problem you have. \$\endgroup\$ – SamGibson Sep 10 '16 at 21:42
  • \$\begingroup\$ ok , i just trying to make led blinking . the led is connected to portF1. \$\endgroup\$ – Ahmed Yasen Sep 10 '16 at 23:45
  • \$\begingroup\$ "i just trying to make led blinking" - OK. I can guess what your problem is, but it would help for me to see your code, as I asked. Are you going to supply your code? If so, please edit your original posting and add your code to the bottom, using the code ("{}") button to format it in a more readable layout. \$\endgroup\$ – SamGibson Sep 11 '16 at 0:24
  • \$\begingroup\$ @SamGibson done \$\endgroup\$ – Ahmed Yasen Sep 11 '16 at 2:03
  • \$\begingroup\$ You're not using the common TI "TivaWare" libraries, so that makes it a bigger job to try to find your bug(s) and it is now night here. :-( There is an obvious mis-spelling in #define PE ox20 but I don't think you use that, so it isn't the cause of your current problem. However that obviously reduces my confidence in the code. || I don't see the code which sets-up the system clock register, but it may be in startup code. || Some of the macros look suspicious to me, but those are not being used. || When you single-step the code, which specific source line causes it to enter FaultISR()? \$\endgroup\$ – SamGibson Sep 11 '16 at 3:03
1
\$\begingroup\$

The short explanation is this:

  • The peripheral clock for the GPIOF module was not enabled correctly, even though you thought the code was doing that. The module is unusable in that state and its registers cannot be accessed.

  • The first attempt to access any registers in that module, led (through a few steps) to the "Hard Fault handler" being called - in CCS, the standard Cortex Hard Fault handler is FaultISR(), as you see in your screenshot.


The longer explanation is this:

You said:

in the function DIO_Init() the port clock is set up.

Unfortunately that code makes a false assumption, which means the port (peripheral) clock for GPIOF is not successfully enabled by that call to DIO_Init().

DIO.h contains:

/*Values of Port Name*/
#define PA 0
#define PB 1
#define PC 2
#define PD 3
#define PE ox20
#define PF 0x21

[As I mentioned previously, the #define for PE should be 0x20 not ox20 but since the problem is with accessing Port F (PF), that problem with the definition of PE is not triggered here.]

Those values for "Port Name" are used in the various macros, to calculate addresses for the base registers for each GPIO port. The base addresses for GPIO Ports E & F are higher up the memory map than those for GPIO Ports A-D. That is why those values for PE and PF are so different than those for PA-PD.

Those values are correct (as far as I can tell) for GPIO port base address calculations (e.g. to set pin direction etc. within that port).

The problem is that those values are also used within the macro ENABLE_PORT_CLOCK in DIO.c here:

/*Enable Port clock macro*/
#define ENABLE_PORT_CLOCK(PORT_ID) SYSCTL_RCGC2_R |= 1 << (PORT_ID)

The code in DIO.c makes the false assumption that the PORT_ID value (from the "Port Name" list earlier) can be used for calculating the GPIO base address and used for calculating the bit number within SYSCTL_RCGC2 to enable the port clocks. That assumption is only true for GPIO ports A-D, but not for ports E & F.

When passed to the macro ENABLE_PORT_CLOCK the PORT_ID value must be the bit number within that register, which is used to enable the port (peripheral) clock. The code passes in a PORT_ID value of 0x21 to try to enable GPIO port F, which is wrong. It must be a value of 0x5 to enable GPIO port F.

[FYI, it should be a value of 0x4 to enable the port (peripheral) clock for GPIO port E.]

[I don't have time now to add the part of the datasheet which explains the register values for SYSCTL_RCGC2 but if you can't find it, I can add that at the weekend - it is in the datasheet for your MCU.]

Therefore the result is that GPIO Port F does not get correctly enabled by the ENABLE_PORT_CLOCK macro, and the first attempt to access any register for that port, which happens in the macro DIO_INIT_DIRECTION, triggers a core fault.

The details of the core fault process are too long to teach here in full, but in brief, the attempted access of a GPIO F register when its clock is not enabled, causes a "Bus Fault". However the Bus Fault handler is not enabled by default by CCS startup (nor by other typical toolchain startup code). Therefore when the Bus Fault occurs, the core detects that the Bus Fault handler has not been enabled, "escalates" this to become a "Forced" Hard Fault, and you see the Hard Fault handler being executed. This means that the problem is similar to the STM32 problem, which I explained in this previous answer which I wrote.


The quick fix, only suitable for enabling GPIO port F, is this:

In DIO.c, replace:

ENABLE_PORT_CLOCK(InitParamters->PortName);

(where the value passed in argument InitParamters->PortName was the value for PF, which is 0x21)

with this:

ENABLE_PORT_CLOCK(5);

since 5 is the correct bit number to set in the SYSCTL_RCGC2 register, to enable the port (peripheral) clock for GPIO port F.

There are various ways to improve the original code, instead of hard-coding the value 5 as in my example above - that value is only correct for enabling GPIO port F, of course. I will leave that code change for you to decide :-)

[One final note: The original code sets several pins on GPIO port F to be outputs, then sets all of those outputs to be open-drain, however it only toggles GPIO pin F1. If that is correct for your hardware then OK, but it seems quite unusual.]

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.