U-boot sections specifications - u-boot

I am currently trying to wrap my head around how u-boot is organized and I was wondering if you could help clarify some of the sections in an config -> include/configs/vexpress_aemv8a.h
#define CONFIG_SYS_TEXT_BASE 0x80000000
/* from what I understand, this is where the code thinks it will be placed in memory */
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
/* I do not understand where this comes into play */
#define CPU_RELEASE_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
/* I do not understand where this comes into play */
#define V2M_BASE 0x80000000
/* I do not understand where this comes into play */
/* Miscellaneous configurable options */
#define CONFIG_SYS_LOAD_ADDR (V2M_BASE + 0x10000000)
/* I do not understand where this comes into play */
I would much appreciate if you could detail where and how these memory zones are used.

Related

Reason for tampering of bitband mapping address at run time

I am using bit banding to set and clear a GPIO6[1] of LPC1857 using Keil.
The mapping address in bit band region to set GPIO6[1] comes 0x43EC4304
The mapping address in bit band region to clear GPIO6[1] comes 0x43EC5384
THE GPIO gets set successfully but does not get cleared.
When checked on debugger, it is observed that mapping address to clear the GPIO6[1] was getting set to 0x43EC5000. Thus the GPIO does not get clear.
Can someone please help understand why this is happening ?
And how can I resolve this mapping address setting to wrong address at run time ?
Following is code snippet:
/*In "main.c"*/
int main()
{
... //System initialization
... //GPIO init
...
Toggle_Peri();
}
/*In "Peri.c"*/
/* Bit band PERIPHERAL definitions */
#define BITBAND_PERI_REF 0x40000000 //Start Address of PeripheRALS
#define BITBAND_PERI_BASE 0x42000000 //Start Address of Peripheral Bit Band Alias Region
/* Basic bit band function definition */
#define BITBAND_PERI(a,b) ((BITBAND_PERI_BASE + ((a-BITBAND_PERI_REF)*(0x20)) + (b*(0x04)))) // Convert GPIO address
#define BITBAND_PERI_SetClearBit(a,b) ((*(volatile uint32_t *) (BITBAND_PERI(a,b))) = 1)
/*Note: Base Address of GPIO = 0x400F 4000*/
#define PERI_GPIO_ADDRESS_S 0x400F6218 //For GPIO6[1] set
#define PERI_GPIO_ADDRESS_C 0x400F629C //For GPIO6[1] clear
#define PERI_GPIO_BIT 1
...
...
...
...
void Toggle_Peri(void)
{
BITBAND_PERI_SetClearBit(PERI_GPIO_ADDRESS_S,PERI_GPIO_BIT); //Set the pin
Delay(0xFFFF);
BITBAND_PERI_SetClearBit(PERI_GPIO_ADDRESS_C,PERI_GPIO_BIT); //Clear the pin
Delay(0xFFFF);
}

GameBoy compiler with system registers and interrupts

I have been spending a lot of time learning GameBoy programming, as I was already familiar with Z80 Assembly I wasn't afraid of jumping into using it. I would (of course) find it much more productive to program in C or C++ however cannot find a full compiler for the GameBoy, the compilers I can find manage everything themselves and do not give access to system registers to the programmer and also have some horrible drawbacks such as 100% CPU utilization and no interrupt support.
Would it be possible to address system registers much like Arduino's AVR compiler? being able to address a CPU or system register simply with its name such as DDRD = %10101011
What would I have to do to add interrupts and system registers into a compiler? All but one system register are only one byte memory addresses and interrupts vectors are of course memory locations, the only one system register that isn't a memory address can only be modified with two Assembly instructions EI and DI but that could be inline functions correct?
The usual tactic is to create your own pointers to system registers. I don't know the address of DDRD, but something like this should to the trick:
volatile unsigned char *reg_DDRD = (unsigned char *)0xE000;
*reg_DDRD = 0xAB;
Most C compilers don't support binary constants but you can use them with some macro hackery. And you can use macros to make slightly more intuitive syntax:
#define DDRD (*reg_DDRD)
DDRD = 0xAB;
There's no sense in modifying the compiler when vanilla C code can work just as well.
Handling interrupts comes down to solving 3 problems. The first is to have the interrupt vector address do a jump to a C function. As that is in ROM you'll need to modify the C runtime environment to initialize that. This gets pretty system dependent, but usually what you'll want to do is add an assembly language file that looks like this:
org 38h ; or wherever the gameboy CPU jumps to on interrupt
jp _intr_function
This should cause the CPU to go to intr_function() in your C program. You may or may not need the leading underscore. And you may not be able to set the destination address in the assembler file with org but instead have to fool around with the linker and sections.
The second problem is that the C function won't necessarily save all the registers it should. You can do this by adding in-line assembly to it, along these lines:
void intr_function()
{
asm(" push af");
asm(" push bc");
asm(" push de");
asm(" push hl");
// ... now do what you like here.
asm(" pop hl");
asm(" pop de");
asm(" pop bc");
asm(" pop af");
}
Finally, the interrupt may have to be acknowledged by manipulating a hardware register. But you can do that in the C code so nothing special about that.
I'm not clear about the issue with wait loops. Standard C compilers don't have such a feature built in. They call main() and if you want to loop it is up to you. It is true that the C-like language used in the Arduino SDK has its own built-in infinite loop that calls the functions you write, but that's not normal C.
First off, you can use GBDK, which is a C compiler and library for the Gameboy. It does provide access to the registers in gb/hardware.h (but that isn't listed in the doc file, since there's no comment for each individual register). It also supplies access to interrupts via methods in gb/gb.h: add_VBL, add_LCD, add_TIM, add_SIO, and add_JOY. (There's also remove methods named remove_).
For reference and/or your own use, here's the contents of gb/hardware.h:
#define __REG volatile UINT8 *
#define P1_REG (*(__REG)0xFF00) /* Joystick: 1.1.P15.P14.P13.P12.P11.P10 */
#define SB_REG (*(__REG)0xFF01) /* Serial IO data buffer */
#define SC_REG (*(__REG)0xFF02) /* Serial IO control register */
#define DIV_REG (*(__REG)0xFF04) /* Divider register */
#define TIMA_REG (*(__REG)0xFF05) /* Timer counter */
#define TMA_REG (*(__REG)0xFF06) /* Timer modulo */
#define TAC_REG (*(__REG)0xFF07) /* Timer control */
#define IF_REG (*(__REG)0xFF0F) /* Interrupt flags: 0.0.0.JOY.SIO.TIM.LCD.VBL */
#define NR10_REG (*(__REG)0xFF10) /* Sound register */
#define NR11_REG (*(__REG)0xFF11) /* Sound register */
#define NR12_REG (*(__REG)0xFF12) /* Sound register */
#define NR13_REG (*(__REG)0xFF13) /* Sound register */
#define NR14_REG (*(__REG)0xFF14) /* Sound register */
#define NR21_REG (*(__REG)0xFF16) /* Sound register */
#define NR22_REG (*(__REG)0xFF17) /* Sound register */
#define NR23_REG (*(__REG)0xFF18) /* Sound register */
#define NR24_REG (*(__REG)0xFF19) /* Sound register */
#define NR30_REG (*(__REG)0xFF1A) /* Sound register */
#define NR31_REG (*(__REG)0xFF1B) /* Sound register */
#define NR32_REG (*(__REG)0xFF1C) /* Sound register */
#define NR33_REG (*(__REG)0xFF1D) /* Sound register */
#define NR34_REG (*(__REG)0xFF1E) /* Sound register */
#define NR41_REG (*(__REG)0xFF20) /* Sound register */
#define NR42_REG (*(__REG)0xFF21) /* Sound register */
#define NR43_REG (*(__REG)0xFF22) /* Sound register */
#define NR44_REG (*(__REG)0xFF23) /* Sound register */
#define NR50_REG (*(__REG)0xFF24) /* Sound register */
#define NR51_REG (*(__REG)0xFF25) /* Sound register */
#define NR52_REG (*(__REG)0xFF26) /* Sound register */
#define LCDC_REG (*(__REG)0xFF40) /* LCD control */
#define STAT_REG (*(__REG)0xFF41) /* LCD status */
#define SCY_REG (*(__REG)0xFF42) /* Scroll Y */
#define SCX_REG (*(__REG)0xFF43) /* Scroll X */
#define LY_REG (*(__REG)0xFF44) /* LCDC Y-coordinate */
#define LYC_REG (*(__REG)0xFF45) /* LY compare */
#define DMA_REG (*(__REG)0xFF46) /* DMA transfer */
#define BGP_REG (*(__REG)0xFF47) /* BG palette data */
#define OBP0_REG (*(__REG)0xFF48) /* OBJ palette 0 data */
#define OBP1_REG (*(__REG)0xFF49) /* OBJ palette 1 data */
#define WY_REG (*(__REG)0xFF4A) /* Window Y coordinate */
#define WX_REG (*(__REG)0xFF4B) /* Window X coordinate */
#define KEY1_REG (*(__REG)0xFF4D) /* CPU speed */
#define VBK_REG (*(__REG)0xFF4F) /* VRAM bank */
#define HDMA1_REG (*(__REG)0xFF51) /* DMA control 1 */
#define HDMA2_REG (*(__REG)0xFF52) /* DMA control 2 */
#define HDMA3_REG (*(__REG)0xFF53) /* DMA control 3 */
#define HDMA4_REG (*(__REG)0xFF54) /* DMA control 4 */
#define HDMA5_REG (*(__REG)0xFF55) /* DMA control 5 */
#define RP_REG (*(__REG)0xFF56) /* IR port */
#define BCPS_REG (*(__REG)0xFF68) /* BG color palette specification */
#define BCPD_REG (*(__REG)0xFF69) /* BG color palette data */
#define OCPS_REG (*(__REG)0xFF6A) /* OBJ color palette specification */
#define OCPD_REG (*(__REG)0xFF6B) /* OBJ color palette data */
#define SVBK_REG (*(__REG)0xFF70) /* WRAM bank */
#define IE_REG (*(__REG)0xFFFF) /* Interrupt enable */
These are done in the same way as George Phillips's answer, and thus can be used like normal variables.
The code that is used by GBDK to add and remove interrupts is found in libc\gb\crt0.s, but I don't know enough of assembly to include the relevant sections in this post.
I'm not sure about how to avoid the busy loop either.

USB Interrupt Masks not loading STM32L151CC

I'm currently encountering a strange issue with the STM USB libraries. I am able to successfully load firmware onto the STM32L152D-EVAL board (which uses an STM32L152ZD), however, I am unable to modify the same code to work on my form-factor board, which uses the aforementioned STM32L151CC.
After stepping through the code with the debugger (a ULINK2, using the KEIL uVision4 IDE), I noticed that the code would crash while setting the interrupt mask in the function USB_SIL_Init()
uint32_t USB_SIL_Init(void)
{
/* USB interrupts initialization */
/* clear pending interrupts */
_SetISTR(0);
wInterrupt_Mask = IMR_MSK;
/* set interrupts mask */
_SetCNTR(wInterrupt_Mask);
return 0;
}
More specifically, _SetCNTR(wInterrupt_Mask); is what gives me the error. I haven't changed the value of IMR_MSK between either board. It's value is given as
#define IMR_MSK (CNTR_CTRM | CNTR_WKUPM | CNTR_SUSPM | CNTR_ERRM | CNTR_SOFM \
| CNTR_ESOFM | CNTR_RESETM )
which is 0xBF00
_SetCNTR is defined as follows
#define _SetCNTR(wRegValue) (*CNTR = (uint16_t)wRegValue)
With CNTR being defined as
/* Control register */
#define CNTR ((__IO unsigned *)(RegBase + 0x40))
And RegBase is
#define RegBase (0x40005C00L) /* USB_IP Peripheral Registers base address */
I'm currently looking through STM's documentation on this, but I can't seem to find anything specifically relating to the default states for the two different chips. I'm guessing it has something to do with the base address, however the Datasheet shows that this is the correct address.
Can anyone help me out on this?
Thanks!

Where can I find the linker command file for the MSP430G2553?

I'm using the MSPGCC to compile and link my programs. I'd like to see how the hardware addresses are assigned in the linker command file. Inside the header file for my device I found these lines:
/* External references resolved by a device-specific linker command file */
#define SFR_8BIT(address) extern volatile unsigned char address
#define SFR_16BIT(address) extern volatile unsigned int address
Further on in the file I found lines like this under the GPIO section:
SFR_8BIT(P1IN); /* Port 1 Input */
SFR_8BIT(P1OUT); /* Port 1 Output */
SFR_8BIT(P1DIR); /* Port 1 Direction */
SFR_8BIT(P1IFG); /* Port 1 Interrupt Flag */
What I'd like to see is how P1IN is defined. I'm trying to get a better understanding of what it is so I can use it.
I realize it can be used like this:
P1OUT &= 0xF7; // clear bit 3
I'd like to find the linker file so I can better understand how the address is being assigned. I know I can just look at the data sheet to see what it is, but I'd like to know how the linker is finding it.
They are defined in the file msp430g2553.cmd.
/************************************************************
* DIGITAL I/O Port1/2 Pull up / Pull down Resistors
************************************************************/
P1IN = 0x0020;
P1OUT = 0x0021;
...
PS: I'm using CCS. The file is located at path\to\ccs\ccs_base\msp430\include along with the header file msp430g2553.h.

Writing Device Drivers for Microcontrollers, where to define IO Port pins?

I always seem to encounter this dilemma when writing low level code for MCU's.
I never know where to declare pin definitions so as to make the code as reusable as possible.
In this case Im writing a driver to interface an 8051 to a MCP4922 12bit serial DAC.
Im unsure how/where I should declare the pin definitions for The CS(chip select) and LDAC(data latch) for the DAC. At the moment there declared in the header file for the driver.
Iv done a lot of research trying to figure out the best approach but havent really found anything.
Im basically want to know what the best practices... if there are some books worth reading or online information, examples etc, any recommendations would be welcome.
Just a snippet of the driver so you get the idea
/**
#brief This function is used to write a 16bit data word to DAC B -12 data bit plus 4 configuration bits
#param dac_data A 12bit word
#param ip_buf_unbuf_select Input Buffered/unbuffered select bit. Buffered = 1; Unbuffered = 0
#param gain_select Output Gain Selection bit. 1 = 1x (VOUT = VREF * D/4096). 0 =2x (VOUT = 2 * VREF * D/4096)
*/
void MCP4922_DAC_B_TX_word(unsigned short int dac_data, bit ip_buf_unbuf_select, bit gain_select)
{
unsigned char low_byte=0, high_byte=0;
CS = 0; /**Select the chip*/
high_byte |= ((0x01 << 7) | (0x01 << 4)); /**Set bit to select DAC A and Set SHDN bit high for DAC A active operation*/
if(ip_buf_unbuf_select) high_byte |= (0x01 << 6);
if(gain_select) high_byte |= (0x01 << 5);
high_byte |= ((dac_data >> 8) & 0x0F);
low_byte |= dac_data;
SPI_master_byte(high_byte);
SPI_master_byte(low_byte);
CS = 1;
LDAC = 0; /**Latch the Data*/
LDAC = 1;
}
This is what I did in a similar case, this example is for writing an I²C driver:
// Structure holding information about an I²C bus
struct IIC_BUS
{
int pin_index_sclk;
int pin_index_sdat;
};
// Initialize I²C bus structure with pin indices
void iic_init_bus( struct IIC_BUS* iic, int idx_sclk, int idx_sdat );
// Write data to an I²C bus, toggling the bits
void iic_write( struct IIC_BUS* iic, uint8_t iicAddress, uint8_t* data, uint8_t length );
All pin indices are declared in an application-dependent header file to allow quick overview, e.g.:
// ...
#define MY_IIC_BUS_SCLK_PIN 12
#define MY_IIC_BUS_SCLK_PIN 13
#define OTHER_PIN 14
// ...
In this example, the I²C bus implementation is completely portable. It only depends on an API that can write to the chip's pins by index.
Edit:
This driver is used like this:
// main.c
#include "iic.h"
#include "pin-declarations.h"
main()
{
struct IIC_BUS mybus;
iic_init_bus( &mybus, MY_IIC_BUS_SCLK_PIN, MY_IIC_BUS_SDAT_PIN );
// ...
iic_write( &mybus, 0x42, some_data_buffer, buffer_length );
}
In one shop I worked at, the pin definitions were put into a processor specific header file. At another shop, I broke the header files into themes associated with modules in the processor, such as DAC, DMA and USB. A master include file for the processor included all of these themed header files. We could model different varieties of the same processor by include different module header files in the processor file.
You could create an implementation header file. This file would define I/O pins in terms of the processor header file. This gives you one layer of abstraction between your application and the hardware. The idea is to loosely couple the application from hardware as much as possible.
If only the driver needs to know about the CS pin, then the declaration should not appear in the header, but within the driver module itself. Code re-use is best served by hiding data at the most restrictive scope possible.
In the event that an external module needs to control CS, add an access function to the device driver module so that you have single point control. This is useful if during debugging you need to know where and when an I/O pin is being asserted; you only have one point to apply instrumentation or breakpoints.
The answer with the run-time configuration will work for a decent CPU like ARM, PowerPC...but the author is running a 8051 here. #define is probably the best way to go. Here's how I would break it down:
blah.h:
#define CSN_LOW() CS = 0
#define CSN_HI() CS = 1
#define LATCH_STROBE() \
do { LDAC = 0; LDAC = 1; } while (0)
blah.c:
#include <blah.h>
void blah_update( U8 high, U8 low )
{
CSN_LOW();
SPI_master_byte(high);
SPI_master_byte(low);
CSN_HI();
LATCH_STROBE();
}
If you need to change the pin definition, or moved to a different CPU, it should be obvious where you need to update. And it's also helps when you have to adjust the timing on the bus (ie. insert a delay here and there) as you don't need to change all over the place. Hope it helps.

Resources