¿La forma correcta de almacenar una dirección de registro en ARM Cortex M4?

0

Estoy escribiendo un programa en STM32F4 Discovery donde tengo que almacenar la dirección del registro CCR del temporizador en un puntero y luego cambiar el registro a través de este puntero, es decir,

volatile uint32_t* tim_ccr_reg = reinterpret_cast<uint32_t*>(TIM4_BASE + 0x34);
// 0x34 = offset of CCR1 register
*tim_ccr_reg = 1999; // Set CCR1 to 1999

Cuando pruebo esto solo en un "programa vacío", funciona, pero cuando uso todo mi programa (junto con todas las demás funciones que implementé) causa una falla en una de esas asignaciones. Ahora estoy averiguando si es mi otro código el que desplaza algo en la memoria o si estoy guardando la dirección de registro de manera incorrecta y solo se muestra cuando se carga un programa más complejo. En la documentación que leí

  

La forma más sencilla de implementar variables asignadas a la memoria es usar punteros para direcciones fijas.

#define PORTBASE 0x40000000
unsigned int volatile * const port = (unsigned int *) PORTBASE;
  

El puerto variable es un puntero constante a un volatile sin signo   entero, por lo que podemos acceder al registro mapeado en memoria usando:

*port = value; /* write to port */
value = *port; /* read from port */
  

Este enfoque se puede usar para acceder a registros de 8, 16 o 32 bits, pero asegúrese de declarar la variable con el tipo apropiado para su tamaño, es decir, int sin signo para registros de 32 bits, sin signo corto para 16 bits, y sin firmar char para 8 bits.   También debe asegurarse de que los registros asignados en memoria se encuentren en los límites de dirección apropiados, por ejemplo. o bien todos alineados por palabra, o alineados en sus límites de tamaño natural, es decir, los registros de 16 bits deben estar alineados en las direcciones de media palabra (pero tenga en cuenta que ARM recomienda que todos los registros, cualquiera sea su tamaño, estén alineados en los límites de palabra.

enlace

Luego fui a ver la documentación de los registros CCR para los temporizadores y dice

ahoranoestoyseguro,¿elregistrosiempreesde32bitsysoloseusan16bitsenalgunostemporizadoresoenalgunoscasosseregistrasolode16bitsytengoqueusarunpunterode16bitsparaescribir¿Qué?

Encualquiercaso,megustaríasabercuáleslaformacorrectadeguardarelregistroCCRdeltemporizadorenunavariable.SihagounsegundoclicenCCR1enelsiguientecomando

TIM4->CCR1=1999;

yhagaclicen"ir a definición" me lleva a un fragmento de código extraño

/** \brief  ITM Send Character

    This function transmits a character via the ITM channel 0.
    It just returns when no debugger is connected that has booked the output.
    It is blocking when a debugger is connected, but the previous character send is not transmitted.

    \param [in]     ch  Character to transmit
    \return             Character to transmit
 */
static __INLINE uint32_t ITM_SendChar (uint32_t ch)
{
  if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)  &&      /* Trace enabled */
      (ITM->TCR & ITM_TCR_ITMENA_Msk)                  &&      /* ITM enabled */
      (ITM->TER & (1UL << 0)        )                    )     /* ITM Port #0 enabled */
  {
    while (ITM->PORT[0].u32 == 0);
    ITM->PORT[0].u8 = (uint8_t) ch;
  }
  return (ch);
}

Estoy (muy) confundido.

    
pregunta Terraviper-5

1 respuesta

0

En su forma más básica, emite la dirección como un "puntero a valor de 32 bits", elimine la referencia y obtenga el valor.

x=*((int*)(0x40000800+0x34))

(int *) es la conversión, lo que hace que el número sea un puntero que apunta a un tipo int.

* (....) es desreferir el puntero.

0x40000800 + 0x34 está entre paréntesis para evitar un error de adición. La conversión tiene predecencia sobre la adición y la adición de un entero a un puntero no es lo mismo que la suma de enteros.

Para ir un paso más allá, define los periféricos como estructuras. El compilador debe garantizar que se llevará a cabo en la memoria como la secuencia que escribe. No olvide que las estructuras son definiciones virtuales como 'int'. Por ejemplo:

struct TIMg_st {volatile u32 CR1,bos0,SMCR,DIER,SR,EGR,CCMR1,bos1,CCER,CNT,PSC,ARR,bos2,CCR1,bos3[6],OR;};

Cuando crea un puntero que apunta a esa estructura (por lo que no es un tipo int esta vez), por ejemplo:

(struct TIMg_st*)0x40000800

Puedes alcanzar sus elementos sin problemas. Por ejemplo:

*((struct TIMg_st*)0x40000800).CCR1

O, para una secuencia de comandos más fácil;

((struct TIMg_st*)0x40000800)->CCR1

Para facilitar las cosas, simplemente conviértalo en una definición:

#define TIM4 ((struct TIMg_st*)0x40000800)

Así que ahora es solo

TIM4->CCR1

y esto es simplemente un valor de 32 bits sin firmar. El valor en el registro puede ser de 16 u 8 bit, eso no es un problema. Lo importante es su ancho de asignación y usted diseña la estructura de acuerdo con eso. Todos los elementos de la estructura son uint32 porque están asignados a 32 bits.

    
respondido por el Ayhan

Lea otras preguntas en las etiquetas