no puede leer los registros de la serie tiva c en el modo de depuración

1

Estoy utilizando Code Composer Studio versión 6.1 con TM4C123GH6PM. Cuando se duplica y se ejecuta, va a una función llamada FaultISR () y luego se bloquea en un bucle infinito Al intentar ver los valores de los registros, muestra un mensaje de error en lugar del valor del registro:

  

Error: no se puede leer

y en la consola muestra:

  

CORTEX_M4_0: Bloqueo de memoria de lectura de problemas en 0x400253fc en la página 0 de Longitud 0x4: Ocurrió un error en el puerto de depuración.

como dice la siguiente imagen.

editar

eseesmicódigo:Esunledparpadeantequeconstadecuatroarchivos: -DIO.hyDIO.c:queesuncontroladorparaelhardwaredeentrada/salida -Reg_Macros.h -blink.c:laaplicación

  

DIO.h

#ifndefDIO_H_#defineDIO_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 ++){
        }
    }
}
    
pregunta Ahmed Yasen

1 respuesta

1

La breve explicación es esta:

  • El reloj periférico para el módulo GPIOF no se habilitó correctamente, aunque pensaste que el código lo estaba haciendo. El módulo no se puede usar en ese estado y no se puede acceder a sus registros.

  • El primer intento de acceder a cualquier registro en ese módulo, condujo (a través de unos pocos pasos) al "Controlador de falla dura" que se llama. En CCS, el controlador de falla dura de Cortex estándar es FaultISR() , como usted ver en tu captura de pantalla.


La explicación más larga es esta:

Has dicho:

  

en la función DIO_Init () se configura el reloj del puerto.

Desafortunadamente, el código hace una suposición falsa, lo que significa que el reloj del puerto (periférico) para GPIOF no está habilitado con éxito por esa llamada a DIO_Init() .

DIO.h contiene:

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

[Como mencioné anteriormente, el #define para PE debe ser 0x20 no ox20 , pero como el problema es acceder al Puerto F (PF), ese problema con la definición de PE no se activa aquí.]

Esos valores para "Nombre de puerto" se utilizan en las distintas macros, para calcular las direcciones de los registros base para cada puerto GPIO. Las direcciones base para GPIO Ports E & F están más arriba en el mapa de memoria que los de los puertos GPIO A-D. Es por eso que los valores para PE y PF son tan diferentes a los de PA-PD.

Esos valores son correctos (por lo que puedo decir) para los cálculos de la dirección base del puerto GPIO (por ejemplo, para establecer la dirección del pin, etc. dentro de ese puerto).

El problema es que esos valores se también se utilizan dentro de la macro ENABLE_PORT_CLOCK en DIO.c aquí:

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

El código en DIO.c hace la suposición falsa de que el valor PORT_ID (de la lista de "Nombre de puerto" anterior) se puede usar para calcular la dirección de base GPIO y para calcular la número de bit dentro de SYSCTL_RCGC2 para habilitar los relojes de puerto. Esa suposición es solo para los puertos GPIO A-D, pero no para los puertos E y amp; F.

Cuando se pasa a la macro ENABLE_PORT_CLOCK , el valor de PORT_ID debe ser el número de bit dentro de ese registro, que se usa para habilitar el reloj del puerto (periférico). El código pasa un valor PORT_ID de 0x21 para intentar habilitar el puerto F de GPIO, que es incorrecto . Debe ser un valor de 0x5 para habilitar el puerto F de GPIO.

[FYI, debe ser un valor de 0x4 para habilitar el reloj del puerto (periférico) para el puerto E de GPIO]

[No tengo tiempo ahora para agregar la parte de la hoja de datos que explica los valores de registro para SYSCTL_RCGC2 , pero si no puede encontrarla, puedo agregarla el fin de semana; está en la hoja de datos de tu MCU.]

Por lo tanto, el resultado es que el GPIO Port F no se habilita correctamente con la macro ENABLE_PORT_CLOCK , y el primer intento de acceder a cualquier registro para ese puerto, lo que sucede en la macro DIO_INIT_DIRECTION , provoca un fallo en el núcleo.

Los detalles del proceso de falla de núcleo son demasiado largos para enseñarlos aquí en su totalidad, pero en resumen, el intento de acceso de un registro GPIO F cuando su reloj no está habilitado, causa un "Fallo de bus". Sin embargo, el controlador de fallas de bus no está habilitado de forma predeterminada por el inicio de CCS (ni por otro código de inicio típico de la cadena de herramientas). Por lo tanto, cuando se produce la falla de bus, el núcleo detecta que el controlador de falla de bus no se ha habilitado, "escala" esto para convertirse en una falla dura "forzada", y usted ve que se está ejecutando el controlador de falla dura. Esto significa que el problema es similar al problema STM32, que expliqué en esta respuesta anterior que escribí.


La solución rápida, solo adecuada para habilitar el puerto F de GPIO, es esta:

En DIO.c, reemplaza:

ENABLE_PORT_CLOCK(InitParamters->PortName);

(donde el valor pasado en el argumento InitParamters->PortName fue el valor para PF , que es 0x21 )

con esto:

ENABLE_PORT_CLOCK(5);

ya que 5 es el número de bit correcto para establecer en el registro SYSCTL_RCGC2 , para habilitar el reloj del puerto (periférico) para el puerto GPIO F.

Hay varias formas de mejorar el código original, en lugar de codificar el valor 5 como en mi ejemplo anterior, ese valor solo es correcto para habilitar el puerto F de GPIO, por supuesto. Dejaré ese cambio de código para que usted decida :-)

[Una nota final: el código original configura varios pines en el puerto F de GPIO para que salgan, luego configura todas esas salidas para que estén abiertas, sin embargo, solo alterna el pin F1 de GPIO. Si eso es correcto para su hardware, entonces está bien, pero parece bastante inusual.]

    
respondido por el SamGibson

Lea otras preguntas en las etiquetas