TM4321GH6PM - why is GPIODATA register initializing itself and how to read and write to it properly? - embedded

Context: I am following a Embedded Systems course that uses the TM4C321GHP6M microcontroller. The IDE being used is the uvision ide by keil. The purpose of the program I am running is to turn on an on-board LED using PF2 and when Switch 1, connected via PF4, is pressed the led will blink. Once switch 1 is released it LED will go back to just being ON.
// BranchingFunctionsDelays.c Lab 6
// Runs on LM4F120/TM4C123
// Use simple programming structures in C to
// toggle an LED while a button is pressed and
// turn the LED on when the button is released.
// This lab will use the hardware already built into the LaunchPad.
// Daniel Valvano, Jonathan Valvano
// January 15, 2016
// built-in connection: PF0 connected to negative logic momentary switch, SW2
// built-in connection: PF1 connected to red LED
// built-in connection: PF2 connected to blue LED
// built-in connection: PF3 connected to green LED
// built-in connection: PF4 connected to negative logic momentary switch, SW1
#include "TExaS.h"
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_PUR_R (*((volatile unsigned long *)0x40025510))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC2_GPIOF 0x00000020 // port F Clock Gating Control
// basic functions defined at end of startup.s
void DisableInterrupts(void); // Disable interrupts
void EnableInterrupts(void); // Enable interrupts
void Delay100ms(unsigned long time);
void init(void);
int main(void){
TExaS_Init(SW_PIN_PF4, LED_PIN_PF2); // activate grader and set system clock to 80 MHz
init();// initialization goes here
EnableInterrupts(); // enable interrupts for the grader
while(1){
unsigned long in;
Delay100ms(1);
in = GPIO_PORTF_DATA_R & 0x10; //read switch
if(in == 0x00){//if PF4 == 0 (switch is pressed)
GPIO_PORTF_DATA_R ^= 0x04; //toggle PF2
}
else{//if PF4 == 1 (switch not pressed)
GPIO_PORTF_DATA_R = 0x04; //set PF2 so LED is ON
}
}
}
void init(void){
SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF; //turn on clock for Port F
Delay100ms(1);
GPIO_PORTF_AMSEL_R = 0x00; //clear PF4 and PF2 bits in port F AMSEL to disable analog
GPIO_PORTF_PCTL_R = 0x00; //clear PF4 and PF2 bit fields in Portf PCTL to config as GPIO
GPIO_PORTF_DIR_R = 0x04; //Set port F dir reg so PF4 is in and PF2 is out
GPIO_PORTF_AFSEL_R = 0x00; //clear PF4 and PF2 bits in port F AFSEL to disable alt func
GPIO_PORTF_DEN_R = 0x14; //set PF4 and PF2 bits in Port F DEN to enable digital
GPIO_PORTF_PUR_R = 0x10; //set PF4 bit in Port F PUR to activate internal pullup
GPIO_PORTF_DATA_R = 0x04; //set PF2 bit in Port F DATA so the LED is init on
PF2 = 0x20;
}
void Delay100ms(unsigned long time){
unsigned long i = 1333333;
while(time > 0){
while(i > 0){
i--;
}
time--;
}
}
For some reason once the program goes to the init() function and steps over SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF; and then Delay100ms(1); the register GPIO_PORTF_DATA_R is initialized with value 0x011. I am not sure what is causing this. Additionally when I attempt to set GPIO_PORTF_DATA_R = 0x04 it then holds the value 0x15? This behavior is very strange and after reading through the data sheet I can see that GPIODATA is read and written to in a unconventional way. For reference please see pages 662 and 654. Would anyone be able to explain this behavior and how I could properly read and write to this register?

This line:
SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF; //turn on clock for Port F
enables the GPIOF clock. When the clock for a peripheral is not running its registers cannot be read or written. So in the debugger you do not see the register value until after the clock is enabled.
Although the reset state of GPIODATA is documented as 0x00000000, that is only true for output the default state of GPIODIR sets every GPIO pin to an input. So 0x11 simply reflects the input state of that port, and PF0 and PF4 happen to be in the logic-high state.
You would need to consult the board schematic to determine what is connected to those pins and why they might be in the high state, but you have already mentioned that PF4 is connected to SW1, and the code sets that pin as an input with internal pull-up. I am guessing that this is a Tiva LaunchPad board having:
Pressing the SW1 push-button will pull the pin low, and the PF4 pit will become zero. The internal pull-up resistor is enabled by default for PF4, so it is not floating even though you have not yet configured it at that point. PF0 GPIOPUR default is floating (per table 10-8), so unless it is configured explicitly to pull-up, its state is indeterminate when connected as on the LaunchPad to SW2.
With respect to perceived "unconventional" behaviour, all peripheral registers on any MCU behave as defined by their manufacturer documentation according to the hardware design. Hardware registers are not RAM (even when memory-mapped) and need not behave like RAM. In particular, unlike RAM, they may have deterministic reset state, and be either read-write, read-only, or write-only. Writing a bit need not modify that bit, registers may change value independently of reads or writes by code.

Related

PIC16F877 display the result of ADC on LEDs with C language using MPLAB

I used PIC16F877 and my purpose is to choose CHANNEL 4 to display the analogue input AN4 value on PortD leds. The approximate value is about 1V. I wrote a code and however, no matter how I ran my code, there're not reaction with the GPIO monitor.
By the way, do I write ReadADC1() in the while(1){} loop? I tried that, but there's no help. Thanks.
#include <xc.h>
#define LEDs PORTD
#include "prologue.c"
unsigned char ReadADC1(void) {
ADCON0 |= 0b00000010;
while ( (ADCON0 & 0b00000010) );
return ADRESH;
}
main ()
{
// declare variables if any required
TRISA= 0B00100000;
ANSEL=0B00010000;
ADCON0 = 0b11010001;
ADCON1 = 0b10000000;
LEDs=ReadADC1();
//*** your code for initialisation if required
//*** end of your initialisation
//*** your code for the superloop
while (1) {
}
//*** end of the superloop
}
There's no reaction with the GPIO pins monitor. I restarted the IDE many times.
By default all ports are configured as an input. If you want want use a port as an output you had to change the configuration:
TRISD = 0x00;
Another issue:
There is no ANSEL register in this controller, you had to do the selection (digital or analog input) with ADCON1register.

UDR register always reads 0xFF

I have an ATTiny that is supposed to receive commands over UART. I have a simple display of eight LEDs that should show the contents of the most recent byte received. I am using an interrupt to read data as it is received. No matter what data I send UDR always reads 0xFF in the interrupt. I know the interrupt is being triggered since the display changes from 0x00 to 0xFF, but it never displays the value I sent over the serial bus.
This is how I enable UART.
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1U << U2X);
#else
UCSRA &= ~(1U << U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
This is the code in the interrupt. I have tested display() and it functions correctly on its own thus implying message is always 0xFF.
ISR(USART_RXC_vect) {
uint8_t message = UDR;
display(message);
}
I am confident that my computer is sending the correct information, but I have only tested it with a pseudo-terminal to print out the sent bytes. I intend to snoop the hardware connection with an oscilloscope, but I don't believe that is the issue. Is there something that is causing UDR to always read as 0xFF?
Edit:
I have snooped the connection with an oscilloscope and have verified that the computer is sending the correct data, at the correct rate. However, the ATTiny is not operating at the correct baud rate. At 2400 baud pulses should be about 400 microseconds long, however the microcontroller is producing pulses over 3 milliseconds long. This explains why it would always read 0xFF, the computer would send nearly the entire byte when the controller thought it was receiving the start bit, when the controller tried to read the remaining data the lines would be undriven, resulting in it reading all ones. I still don't know why this is the case as I believe I am properly setting the baud rate on the controller.
Edit:
The issue has been resolved. By default the clock prescaler is set to 8, so the device was only operating at 1MHz, not 8MHz. Setting the clock prescaler to 1 solved the problem.
There can be several problems with uart communication. First check some things:
Is controller configured with the right clock?
Internal/External
Is F_CPU defined for <util/setbaud.h>?
Is BAUD defined for <util/setbaud.h>?
Are you using a controller like ATmega16 that has special register access?
If you are using an external clock (that should not be devided) is CKDIV8 disabled in FUSES or in special registers at some controllers?
Is:
Baudrate,
Paritybit,
Stopbit
setup corret on Transmitter and Receiver
Debug:
If you are using a PC for communication, create a loopback at the UART adapter and check with a terminal (TeraTerm, Putty, ...) if the messages you send are received correctly.
You also can enable the TX controller and check if loopback is working on your uC.
If it is possible try to write the received data to some leds to check if some date is received
Is GND betweend receiver and transmitter connected?
Are the voltage levels between transmitter and receiver the same?
Do transmitter and receiver have its own source? (Then do not connect VCC!)
Check if the clock on the controller is correct (switch on an led with _delay_ms() function every second)
Example Program
#define F_CPU 12000000UL
#define BAUD 9600UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/setbaud.h>
ISR(USART_RXC_vect)
{
volatile unsigned char message = UDR;
// If it is possible try to write the received data to
// LEDs (if there are some at your board)
display(message);
}
int main()
{
// To allow changes to clock prescaler it is necessary to set the
// CCP register (Datasheet page 23)!
CCP = 0xD8;
// RESET the clock prescaler from /8 to /1 !!!!
// Or it is necessary to divide F_CPU through the CLK_PRESCALER
CLKPSR = 0x00;
UBRRH = UBRRH_VALUE;
UBRRL = UBRRL_VALUE;
#if USE_2X
UCSRA |= (1<<U2X);
#else
UCSRA &= ~(1<<U2X);
#endif
// Enable receiver and interrupt
UCSRB = (1U << RXEN) | (1U << RXCIE);
// No parity, 8 Data Bits, 1 Stop Bit
// Not necessary! Mostly ATmega controller
// have 8 bit mode initialized at startup
//UCSRC = (1U << UCSZ1) | (1U << UCSZ0);
// If you are using ATmega8/16 it is necessary to do some
// special things to write to the UBRRH and UCSRC register!
// See ATmega16 datasheet at page 162
// Do not forget to enable interrupts globally!
sei();
while(1);
}
Please explain what the display() function is doing...

Erasing a flash on TIVA TM4C123 Microcontroller

I have been trying to understand the following code which is writing to micro controller flash. The Microcontroller is TIVA ARM Cortex M4. I have read the Internal Memory Chapter 8 of Tiva™ TM4C123GH6PM Microcontroller Data sheet. At high level I understand Flash Memory Address (FMA), Flash Memory Data (FMD), and Flash Memory Control (FMC) and Boot Configuration (BOOTCFG).
Below are definitions for some of the variable used in the function.
#define FLASH_FMA_R (*((volatile uint32_t *)0x400FD000))
#define FLASH_FMA_OFFSET_MAX 0x0003FFFF // Address Offset max
#define FLASH_FMD_R (*((volatile uint32_t *)0x400FD004))
#define FLASH_FMC_R (*((volatile uint32_t *)0x400FD008))
#define FLASH_FMC_WRKEY 0xA4420000 // FLASH write key (KEY bit of FLASH_BOOTCFG_R set)
#define FLASH_FMC_WRKEY2 0x71D50000 // FLASH write key (KEY bit of FLASH_BOOTCFG_R cleared)
#define FLASH_FMC_MERASE 0x00000004 // Mass Erase Flash Memory
#define FLASH_FMC_ERASE 0x00000002 // Erase a Page of Flash Memory
#define FLASH_FMC_WRITE 0x00000001 // Write a Word into Flash Memory
#define FLASH_FMC2_R (*((volatile uint32_t *)0x400FD020))
#define FLASH_FMC2_WRBUF 0x00000001 // Buffered Flash Memory Write
#define FLASH_FWBN_R (*((volatile uint32_t *)0x400FD100))
#define FLASH_BOOTCFG_R (*((volatile uint32_t *)0x400FE1D0))
#define FLASH_BOOTCFG_KEY 0x00000010 // KEY Select
This function is used to erase a section of the flash. The function is called from a start address to and end address. I have not fully comprehended how this code works.
//------------Flash_Erase------------
// Erase 1 KB block of flash.
// Input: addr 1-KB aligned flash memory address to erase
// Output: 'NOERROR' if successful, 'ERROR' if fail (defined in FlashProgram.h)
// Note: disables interrupts while erasing
int Flash_Erase(uint32_t addr){
uint32_t flashkey;
if(EraseAddrValid(addr)){
DisableInterrupts(); // may be optional step
// wait for hardware idle
while(FLASH_FMC_R&(FLASH_FMC_WRITE|FLASH_FMC_ERASE|FLASH_FMC_MERASE)){
// to do later: return ERROR if this takes too long
// remember to re-enable interrupts
};
FLASH_FMA_R = addr;
if(FLASH_BOOTCFG_R&FLASH_BOOTCFG_KEY){ // by default, the key is 0xA442
flashkey = FLASH_FMC_WRKEY;
} else{ // otherwise, the key is 0x71D5
flashkey = FLASH_FMC_WRKEY2;
}
FLASH_FMC_R = (flashkey|FLASH_FMC_ERASE); // start erasing 1 KB block
while(FLASH_FMC_R&FLASH_FMC_ERASE){
// to do later: return ERROR if this takes too long
// remember to re-enable interrupts
}; // wait for completion (~3 to 4 usec)
EnableInterrupts();
return NOERROR;
}
return ERROR;
}
Questions: How does the function exit out of the two while loops? How are variables FLASH_FMC_WRITE, FLASH_FMC_ERASE, and FLASH_FMC_MERASE changed? Can '0' be written as part of the erase process?
FLASH_FMC_WRITE, FLASH_FMC_ERASE, and FLASH_FMC_MERASE are individual bits in the FLASH_FMC_R register value (a bitfield). Look in the part's reference manual (or maybe datasheet) at the description of the FLASH_FMC_R register and you will find the description of these bits and more.
The while loops repeatedly read the FLASH_FMC_R register value and exit when the specified bits are set. The flash memory controller sets these bits when it's appropriate (read the reference manual).
Erasing flash means setting all bits to 1 (all bytes to 0xFF). Writing flash means setting select bits to 0. You cannot change a bit from 0 to 1 with a write.
You need to erase to do that. This is just the way flash works.

SPI slaveon DSPIC

Working on DSPIC33FJ128MC804
The problem :
I am completely unable to configura the SPI as slave. SPI Interrupt does never fire. if(SPI2STATbits.SPIRBF || SPI2STATbits.SPIROV) is always evaluated as false too.
I tried
with SSEN enabled and disabled, and many other configurations...
The clock is present and generated by an Arduino Uno as master, the pin mapping has been checked 3 times. This device is not subject to the SPI slave CSn errata of this familly.
Does anyone see what I do wrong ? or have a working example as SLAVE ?
// Setup hardware I/Os configuration
SPI_SLAVE_CSN_TRIS = 1; //input
SPI_SLAVE_CLK_TRIS = 1;
SPI_SLAVE_MOSI_TRIS = 1;
SPI_SLAVE_MISO_TRIS = 0; //output
// Setup remapable pins
SPI_SLAVE_MISO_RPN = _RPOUT_SDO2; // configure RP output
RPINR22bits.SDI2R = SPI_SLAVE_MOSI_RP_NUMBER; //configure inputs
RPINR22bits.SCK2R = SPI_SLAVE_CLK_RP_NUMBER;
RPINR23bits.SS2R = SPI_SLAVE_CSN_RP_NUMBER;
IFS2bits.SPI2IF = 0; // Clear interrupt flag
IEC2bits.SPI2IE = 0; // Disable interrupt
// Baudrate configuration (unused in slave mode )
SPI2CON1bits.PPRE = 0b11; //TODO needed in slave mode ?
SPI2CON1bits.SPRE = 0b110;
SPI2CON1bits.DISSCK = 0; // Internal serial clock
SPI2CON1bits.DISSDO = 0; // SDOx is controlled by the module
SPI2CON1bits.MODE16 = 0; // 8 bit mode //TODO check if 16 bit fit's better
SPI2CON1bits.SMP = 0; // 0 when slave
SPI2CON1bits.CKE = 1; // Emits SDO on SCK falling edge (slave samples on rising)
SPI2CON1bits.CKP = 0; // SCK idle state is LOW level
SPI2CON1bits.SSEN = 1;// CSN pin used for slave mode
SPI2CON1bits.MSTEN = 0; // Slave mode is enabled
//SPI2CON2bits.SPIFSD = 1; //we are not in framed mode
SPI2STATbits.SPIEN = 1; // Enable SPI module
//TODO ISR priority
// Write the SPIx Interrupt Priority Control (SPIxIP) bits in the respective IPCx register to set the interrupt priority
SPI2BUF = 0xf3; // Clear data to be transmitted => for test
IFS2bits.SPI2IF = 0; // Clear interrupt flag
IEC2bits.SPI2IE = 1; // Enable interrupt
SOLVED
The RPN pin fucntions where locked in another part of the code I hadn't written.
I was not aware of this functionnality
I have no experience with SPI in slave mode but in general setting the priority of the interrupt on 16 and 32 bit pic MCUs are not optional, it must be set or the interrupt won't fire, at least that's been my experience. Set the IPCx bits relevant for the peripherals you use.
Try finding a code snippet where an interrupt function is defined and use that as a template. It's generally very similar for every peripheral. UART and maybe also the SPI module has a separate send and receive interrupt vector, both must be defined.
Somewhere in the main function, enable the interrupt and set the priority, at least non zero IIRC:
IEC0bits.AD1IE = 1; // Enable adc interrupt
IPC3bits.AD1IP = 4; // set priority above that of the serial port.
For an ADC I use this to define the interrupt. All you need to change is the _ADC1Interrupt part. See the datasheet and XC16 documentation for the correct function name.
// ADC1 interrupt vector
void __attribute__((__interrupt__(auto_psv))) _ADC1Interrupt(void)
{
if( IFS0bits.AD1IF ) // Check interrupt flag
{
}
IFS0bits.AD1IF = 0; // clear interrupt flag to prevent endless interrupts
}

stm32L476RG - how to execute the bootloader from firmware

I am working on a NUCLEO-L476RG board, trying to start the bootloader from my firmware code but its not working for me. here is the code that i am trying to execute :
#include "stm32l4xx.h"
#include "stm32l4xx_nucleo.h"
#include "core_cm4.h"
#include "stm32l4xx_hal_uart.h"
GPIO_InitTypeDef GPIO_InitStructure;
UART_HandleTypeDef UartHandle;
UART_InitTypeDef UART_InitStructre;
void BootLoaderInit(uint32_t BootLoaderStatus){
void (*SysMemBootJump)(void) = (void (*)(void)) (*((uint32_t *) 0x1FFF0004));
if(BootLoaderStatus == 1) {
HAL_DeInit(); // shut down running tasks
// Reset the SysTick Timer
SysTick->CTRL = 0;
SysTick->LOAD = 0;
SysTick->VAL =0;
__set_PRIMASK(1); // Disable interrupts
__set_MSP((uint32_t*) 0x20001000);
SysMemBootJump();
}
}
int main(void)
{
HAL_Init();
__GPIOC_CLK_ENABLE();
GPIO_InitStructure.Pin = GPIO_PIN_13;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
while (1) {
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13)) {
BootLoaderInit(1);
}
}
return 0;
}
What i hope to get after the execution of the firmware is that i can connect to the board with a UART and send commands/get responses from the bootloader. the commands i am trying to use come from here: USART protocol used in the STM32 bootloader.
I don't see and response from the board after connecting with the UART.
Here are some ideas taken from the answers to this question.
HAL_RCC_DeInit();
This is apparently needed to put the clocks back into the state after reset, as the bootloader expects them to be.
__HAL_REMAPMEMORY_SYSTEMFLASH();
Maps the system bootloader to address 0x00000000
__ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
Set the stack pointer from bootloader ROM. Where does your 0x20001000 come from? If it's an arbitrary value, then the stack can clobber the bootloader's variables.
Then there is this alternate solution:
When I want to jump to the bootloader, I write a byte in one of the
backup register and then issue a soft-reset. Then, when the processor
will restart, at the very beginning of the program, it will read this
register.
Note that you need LSI or LSE clock for accessing the backup registers.
Try to avoid using __set_MSP(), as current implementation of this function does NOT allow you to change MSP if it is also the stack pointer which you currently use (and you most likely are). The reason is that this function marks "sp" as clobbered register, so it will be saved before and restored afterwards.
See here - STM32L073RZ (rev Z) IAP jump to bootloader (system memory)
Find your bootloader start address from the reference manual.
Then use the following code.
Make sure you have cleaned and disabled the interrupts before do so.
/* Jump to different address */
JumpAddress = *(__IO uint32_t*) (BootloaderAddress + 4);
Jump_To_Application = (pFunction) JumpAddress;
/* Initialize user application's Stack Pointer */
__set_MSP(*(__IO uint32_t*) ApplicationAddress);
Jump_To_Application();
Please have a look at Official STM32 AppNote as well.