atmega embedded C programming - c

I am trying to learn embedded C programming for atmega. I am stuck with this error called
avr-gcc.exe(0,0): CreateProcess: No such file or directory
I have written a simple C code of about 10 lines.
/*
* RAJESH_AVRC_PROG.c
*
* Created: 6/10/2017 10:33:39 PM
* Author: AMMU_AMMA
*/
#define F_CPU 2000000L
#include <avr/io.h>
#include <avt/delay.>
int main(void)
{
DDRB = 0xFF;
PORTB = 0xFF;
while(1)
{
PORTB = 0xFF;
_delay_ms(1000);
PORTB=0x00;
_delay_ms(1000);
//TODO:: Please write your application code
}
}

If you want to get a quick start, I suggest you use Linux (in a VM or on a separate PC). On Debian/Ubuntu, you can install the required tools on a terminal using:
sudo apt-get install avrdude gcc-avr
You can then use this to compile your files (for atmega32):
avr-gcc -Os -mmcu=atmega32 RAJESH_AVRC_PROG.c -o RAJESH_AVRC_PROG.elf && avr-objcopy -O ihex -j .text -j .data RAJESH_AVRC_PROG.elf RAJESH_AVRC_PROG.hex
You can load the resulting hex file onto your AVR.

Related

MSP430F5529 | MSPGCC Building/Compiling manually | Cannot execute Simple Program

i have just started to work with the MSP430F5529.
I have downloaded the msp430-gcc compiler and tried to compile the folowing short program:
#include <msp430f5529.h>
int main(void)
{
WDTCTL = WDTPW | WDTHOLD;
P1DIR = BIT0;
P1OUT = 0x00;
P1REN = 0x00;
while(1)
{
P1OUT = BIT0;
};
return 0;
}
I have compiled it via:
C:\ProgrammingTools\ti\msp430-gcc\bin\msp430-elf-gcc.exe -Wall main.c -IC:\ProgrammingTools\ti\msp430-gcc\include\ -o MSP430.out
I have flashed it onto the board with the MSPFlasher 1.3.20, it did not show any errors, but the LED did not turn on. I have also tried to verify and flash it with the UniFlash Tool (V8.1.1.41.46). Ther verification was successful, but the result of flashing was the same, the LED did not do anything. Has anyone had the same problem?
It seems that you have to link the correct linker script.
The correct way of building would have been:
C:\ProgrammingTools\ti\msp430-gcc\bin\msp430-elf-gcc.exe -I C:\ProgrammingTools\ti\msp430-gcc\include -L C:\ProgrammingTools\ti\msp430-gcc\include -mmcu=msp430f5529 -O2 -g main.c -o MSP430.out
It is also described in the MSP430 GCC Toolcahin User Guide in section 4.6.2 Building Manually with gcc.

How do I run the PWM with wiringPi?? (Issue with pwmMode PWM)

I am trying to run a PWM programm in geany (C language with a Raspberry 4B). I can compile and build the program; however, when I run it the next erro appears:
pinMode PWM: unable to do this when using /dev(gpiomem. Try sudo?
Does anyone have had experience something like this? How can I fix it?
My program is the following:
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define MFOR_MOTOR 25
#define MBACK_MOTOR 24
#define PWM_MOTOR 1
#define ENCODER_A 21
#define ENCODER_B 22
int main (void){
if (wiringPiSetup()==-1)
exit (1) ;
int pwm_user;
wiringPiSetup();
pinMode(MFOR_MOTOR, OUTPUT);
pinMode(MBACK_MOTOR, OUTPUT);
pinMode(PWM_MOTOR, PWM_OUTPUT);
pinMode(ENCODER_A, INPUT);
pinMode(ENCODER_B, INPUT);
printf ("Raspberry Pi wiringPi Motor PWM program\n") ;
printf("PWM from motor: ");
scanf("%d", &pwm_user);
pwmWrite(PWM_MOTOR, pwm_user);
digitalWrite(MFOR_MOTOR, HIGH);
while(1){
digitalRead(ENCODER_A);
}
digitalWrite(MFOR_MOTOR, LOW);
return 0;
}
Thanks #Craig Estey for your help. I "fixed" the problem running the program directly to the terminal in the RaspberryPi so I used the next format for running it
$ nano pwm_motor.c //for creating the programm
$ gcc -Waöö pwm_motor.c -lwiring -o pwm_motor // for compile the programm
$ chmod +x pwm_motor // for build the program
$ sudo ./pwm_motor //for running the program
Maybe is not the best way but it worked for me. if someone else knows another idea I love reading it.

Raspberry PI 3 UART0 Not Transmitting (Bare-Metal)

Introduction
I have been working on writing my own bare metal code for a Raspberry PI as I build up my bare metal skills and learn about kernel mode operations. However, due to the complexity, amount of documentation errors, and missing/scattered info, it has been extremely difficult to finally bring up a custom kernel on the Raspberry PI. However, I finally got that working.
A very broad overview of what is happening in the bootstrap process
My kernel loads into 0x80000, sends all cores except core 0 into an infinite loop, sets up the Stack Pointer, and calls a C function. I can setup the GPIO pins and turn them on and off. Using some additional circuitry, I can drive LEDs and confirm that my code is executing.
The problem
However when it comes to the UART, I have hit a wall. I am using UART0 (PL011). As far as I can tell, the UART is not outputting, although I could be missing it on my scope since I only have an analog oscilloscope. The code gets stuck when outputting the string. I have determined through hours of reflashing my SD card with different YES/NO questions to my LEDs that it is stuck in an infinite loop waiting for the UART Transmit FIFO Full flag to clear. The UART only accepts 1 byte before becoming full. I can not figure out why it is not transmitting the data out. I am also not sure if I have correctly set my baud-rate, but I don't think that would cause the TX FIFO to stay filled.
Getting a foothold in the code
Here is my code. The execution begins at the very beginning of the binary. It is constructed by being linked with symbol "my_entry_pt" from assembly source "entry.s" in the linker script. That is where you will find the entry code. However, you probably only need to look at the last file which is the C code in "base.c". The rest is just bootstrapping up to that. Please disregard some comments/names which don't make sense. This is a port (of primarily the build infrastructure) from an earlier bare-metal project of mine. That project used a RISC-V development board which uses a memory mapped SPI flash to store the binary code of the program.:
[Makefile]
TUPLE := aarch64-unknown-linux-gnu
CC := $(TUPLE)-gcc
OBJCPY := $(TUPLE)-objcopy
STRIP := $(TUPLE)-strip
CFLAGS := -Wall -Wextra -std=c99 -O2 -march=armv8-a -mtune=cortex-a53 -mlittle-endian -ffreestanding -nostdlib -nostartfiles -Wno-unused-parameter -fno-stack-check -fno-stack-protector
LDFLAGS := -static
GFILES :=
KFILES :=
UFILES :=
# Global Library
#GFILES := $(GFILES)
# Kernel
# - Core (Entry/System Setup/Globals)
KFILES := $(KFILES) ./src/kernel/base.o
KFILES := $(KFILES) ./src/kernel/entry.o
# Programs
# - Init
#UFILES := $(UFILES)
export TUPLE
export CC
export OBJCPY
export STRIP
export CFLAGS
export LDFLAGS
export GFILES
export KFILES
export UFILES
.PHONY: all rebuild clean
all: prog-metal.elf prog-metal.elf.strip prog-metal.elf.bin prog-metal.elf.hex prog-metal.elf.strip.bin prog-metal.elf.strip.hex
rebuild: clean
$(MAKE) all
clean:
rm -f *.elf *.strip *.bin *.hex $(GFILES) $(KFILES) $(UFILES)
%.o: %.c
$(CC) $(CFLAGS) $^ -c -o $#
%.o: %.s
$(CC) $(CFLAGS) $^ -c -o $#
prog-metal.elf: $(GFILES) $(KFILES) $(UFILES)
$(CC) $(CFLAGS) $^ -T ./bare_metal.ld $(LDFLAGS) -o $#
prog-%.elf.strip: prog-%.elf
$(STRIP) -s -x -R .comment -R .text.startup -R .riscv.attributes $^ -o $#
%.elf.bin: %.elf
$(OBJCPY) -O binary $^ $#
%.elf.hex: %.elf
$(OBJCPY) -O ihex $^ $#
%.strip.bin: %.strip
$(OBJCPY) -O binary $^ $#
%.strip.hex: %.strip
$(OBJCPY) -O ihex $^ $#
emu: prog-metal.elf.strip.bin
qemu-system-aarch64 -kernel ./prog-metal.elf.strip.bin -m 1G -cpu cortex-a53 -M raspi3 -serial stdio -display none
emu-debug: prog-metal.elf.strip.bin
qemu-system-aarch64 -kernel ./prog-metal.elf.strip.bin -m 1G -cpu cortex-a53 -M raspi3 -serial stdio -display none -gdb tcp::1234 -S
debug:
$(TUPLE)-gdb -ex "target remote localhost:1234" -ex "layout asm" -ex "tui reg general" -ex "break *0x00080000" -ex "break *0x00000000" -ex "set scheduler-locking step"
[bare_metal.ld]
/*
This is not actually needed (At least not on actual hardware.), but
it explicitly sets the entry point in the .elf file to be the same
as the true entry point to the program. The global symbol my_entry_pt
is located at the start of src/kernel/entry.s. More on this below.
*/
ENTRY(my_entry_pt)
MEMORY
{
/*
This is the memory address where this program will reside.
It is the reset vector.
*/
ram (rwx) : ORIGIN = 0x00080000, LENGTH = 0x0000FFFF
}
SECTIONS
{
/*
Force the linker to starting at the start of memory section: ram
*/
. = 0x00080000;
.text : {
/*
Make sure the .text section from src/kernel/entry.o is
linked first. The .text section of src/kernel/entry.s
is the actual entry machine code for the kernel and is
first in the file. This way, at reset, exection starts
by jumping to this machine code.
*/
src/kernel/entry.o (.text);
/*
Link the rest of the kernel's .text sections.
*/
*.o (.text);
} > ram
/*
Put in the .rodata in the flash after the actual machine code.
*/
.rodata : {
*.o (.rodata);
*.o (.rodata.*);
} > ram
/*
END: Read Only Data
START: Writable Data
*/
.sbss : {
*.o (.sbss);
} > ram
.bss : {
*.o (.bss);
} > ram
section_KHEAP_START (NOLOAD) : ALIGN(0x10) {
/*
At the very end of the space reserved for global variables
in the ram, link in this custom section. This is used to
add a symbol called KHEAP_START to the program that will
inform the C code where the heap can start. This allows the
heap to start right after the global variables.
*/
src/kernel/entry.o (section_KHEAP_START);
} > ram
/*
Discard everything that hasn't be explictly linked. I don't
want the linker to guess where to put stuff. If it doesn't know,
don't include it. If this casues a linking error, good. I want
to know that I need to fix something, rather than a silent failure
that could cause hard to debug issues later. For instance,
without explicitly setting the .sbss and .bss sections above,
the linker attempted to put my global variables after the
machine code in the flash. This would mean that ever access to
those variables would mean read a write to the external SPI flash
IC on real hardware. I do not believe that initialized globals
are possible since there is nothing to initialize them. So I don't
want to, for instance, include the .data section.
*/
/DISCARD/ : {
* (.*);
}
}
[src/kernel/entry.s]
.section .text
.globl my_entry_pt
// This is the Arm64 Kernel Header (64 bytes total)
my_entry_pt:
b end_of_header // Executable code (64 bits)
.align 3, 0, 7
.quad my_entry_pt // text_offset (64 bits)
.quad 0x0000000000000000 // image_size (64 bits)
.quad 0x000000000000000A // flags (1010: Anywhere, 4K Pages, LE) (64 bits)
.quad 0x0000000000000000 // reserved 2 (64 bits)
.quad 0x0000000000000000 // reserved 3 (64 bits)
.quad 0x0000000000000000 // reserved 4 (64 bits)
.int 0x644d5241 // magic (32 bits)
.int 0x00000000 // reserved 5 (32 bits)
end_of_header:
// Check What Core This Is
mrs x0, VMPIDR_EL2
and x0, x0, #0x3
cmp x0, #0x0
// If this is not core 0, go into an infinite loop
bne loop
// Setup the Stack Pointer
mov x2, #0x00030000
mov sp, x2
// Get the address of the C main function
ldr x1, =kmain
// Call the C main function
blr x1
loop:
nop
b loop
.section section_KHEAP_START
.globl KHEAP_START
KHEAP_START:
[src/kernel/base.c]
void pstr(char* str) {
volatile unsigned int* AUX_MU_IO_REG = (unsigned int*)(0x3f201000 + 0x00);
volatile unsigned int* AUX_MU_LSR_REG = (unsigned int*)(0x3f201000 + 0x18);
while (*str != 0) {
while (*AUX_MU_LSR_REG & 0x00000020) {
// TX FIFO Full
}
*AUX_MU_IO_REG = (unsigned int)((unsigned char)*str);
str++;
}
return;
}
signed int kmain(unsigned int argc, char* argv[], char* envp[]) {
char* text = "Test Output String\n";
volatile unsigned int* AUXENB = 0;
//AUXENB = (unsigned int*)(0x20200000 + 0x00);
//*AUXENB |= 0x00024000;
//AUXENB = (unsigned int*)(0x20200000 + 0x08);
//*AUXENB |= 0x00000480;
// Set Baud Rate to 115200
AUXENB = (unsigned int*)(0x3f201000 + 0x24);
*AUXENB = 26;
AUXENB = (unsigned int*)(0x3f201000 + 0x28);
*AUXENB = 0;
AUXENB = (unsigned int*)(0x3f200000 + 0x04);
*AUXENB = 0;
// Set GPIO Pin 14 to Mode: ALT0 (UART0)
*AUXENB |= (04u << ((14 - 10) * 3));
// Set GPIO Pin 15 to Mode: ALT0 (UART0)
*AUXENB |= (04u << ((15 - 10) * 3));
AUXENB = (unsigned int*)(0x3f200000 + 0x08);
*AUXENB = 0;
// Set GPIO Pin 23 to Mode: Output
*AUXENB |= (01u << ((23 - 20) * 3));
// Set GPIO Pin 24 to Mode: Output
*AUXENB |= (01u << ((24 - 20) * 3));
// Turn ON Pin 23
AUXENB = (unsigned int*)(0x3f200000 + 0x1C);
*AUXENB = (1u << 23);
// Turn OFF Pin 24
AUXENB = (unsigned int*)(0x3f200000 + 0x28);
*AUXENB = (1u << 24);
// Enable TX on UART0
AUXENB = (unsigned int*)(0x3f201000 + 0x30);
*AUXENB = 0x00000101;
pstr(text);
// Turn ON Pin 24
AUXENB = (unsigned int*)(0x3f200000 + 0x1C);
*AUXENB = (1u << 24);
return 0;
}
Debugging up the this point
So it turns out that all of us were right. My initial trouble shooting in response to #Xiaoyi Chen was wrong. I rebooted back into Raspberry Pi OS to check on a hunch. I was connected to the PI using a 3.3V UART adapter connected to pins 8 (GPIO 14, UART0 TX), 10 (GPIO 15, UART0 RX), and GND(for a common ground of course). I could see the boot messages and a getty login prompt which I could log into. I figured that meant that the PL011 was working, but when I actually checked the process list in htop, I found that getty was actually running on /dev/ttyS0 not /dev/ttyAMA0. /dev/ttyAMA0 was actually being tied to the bluetooth module with the hciattach command in another process listing.
According to the documentation here: https://www.raspberrypi.org/documentation/configuration/uart.md , /dev/ttyS0 is the mini UART while /dev/AMA0 is the PL011, but it also says that UART0 is PL011 and UART1 is the mini UART. Furthermore, the GPIO Pinouts and the BCM2835 documentation say that GPIO Pins 14 and 15 are for the UART0 TX and RX. So something did not add up if I can see the login prompt on pins 14 and 15 when Linux is using the mini UART, but I am supposedly physically connected to the PL011. If I SSHed in and tried to open /dev/ttyAMA0 with minicom, I could see nothing happening. However, if I did the same with /dev/ttyS0, it would conflict with the login terminal. This confirmed to me that /dev/ttyS0 was in fact in use for the boot console.
The Answer
If I set "dtoverlay=disable-bt" in config.txt, the above behavior changed to match expectations. Rebooting the PI made it once again come up with a console on header pins 8 and 10, but checking the process listing showed that this time getty was using /dev/ttyAMA0. If then set "dtoverlay=disable-bt" in config.txt with my custom kernel, the program executed as expected, printing out my string and turned on the second LED. Since the outputs of the PL011 were never actually setup, since it was redirected by some magic, it makes sense that it would not be working as #PMF suggested. This whole deal has just reaffirmed my assertion that the documentation for this so-called "learning computer" is atrocious.
For those who are curious, here are the last few lines from my config.txt:
[all]
dtoverlay=disable-bt
enable_uart=1
core_freq=250
#uart_2ndstage=1
force_eeprom_read=0
disable_splash=1
init_uart_clock=48000000
init_uart_baud=115200
kernel_address=0x80000
kernel=prog-metal.elf.strip.bin
arm_64bit=1
Remaining Questions
A few things still bother me. I could have sworn that I already tried setting "dtoverlay=disable-bt".
Secondly it does seem that this preforms some kind of magic under the hood that is not documented(I know of no documentation for it.) and I do not understand. I can find nothing in the published schematics that redirect the output of GPIO 14 and 15 from the SOC. So ether the schematics are incomplete or there is some proprietary magic taking place inside the SOC which redirects the pins, contradicting the documentation.
I also have questions about precedence when it comes to the config.txt options and setting things up elsewhere.
Anyway, thank you for the help everyone.
My suggestion:
flash your SD card to a rpi distribution to make sure the hardware is still working
if the hardware is good, check the difference of your code with the in-kernel serial driver

Qemu baremetal emulation - how to view UART output?

Question:
How do I get the UART output from a baremetal program run with Qemu?
Background
Here is the command line invocation I have been using:
qemu-system-arm -M xilinx-zynq-a9 -cpu cortex-a9 -nographic -kernel $BUILD_DIR/mm.elf -m 512M -s -S
using machine xilinx-zynq-a9
processor cortex-a9
as this is baremetal, the executable is a self contained ELF file
-m 512M signifies the platform has 512 MiB of RAM
-s is a shortcut for -gdb tcp::1234
-S means freeze CPU at startup
The ELF file I am using (mm.elf) performs a simple matrix multiply operation, and then prints whether it succeeded or failed, and how long it took to run. The ELF was compiled using the Xilinx ARM toolchain. I am using this for software fault injection. Currently I use GDB to ask for the values of the variables which are supposed to be printed. However, as there are many things which could go wrong with printing in the context of fault injection, it would be nice to see what is actually sent over UART.
Related answers:
redirect QEMU window output to terminal running qemu
This has some suggestions I tried, but it isn't applicable because the question was about getting the Linux boot messages in the host terminal window.
How to run a program without an operating system?
This is one isn't very related because it still assumes that the user has a bootloader of some kind. While there must technically be a bootloader for the application to run at all, Xilinx provides this system code in files like boot.S, which are then compiled into the ELF file as code which runs before main.
Things that I have tried:
I tried adding each of these onto the end of my current Qemu command. The results follow the parameters tried.
-serial mon:stdio
nothing
-serial null -serial mon:stdio (because Cortex-A9 has two UARTs)
nothing
the above two with -semihosting added
nothing
-serial stdio
cannot use stdio by multiple character devices
could not connect serial device to character backend 'stdio'
-console=/dev/tty
invalid option
-curses
black screen, no output
Investigation
I looked at the disassembly of the ELF file and verified that the address to which the the UART messages are being written is the same as the Qemu setup expects (info mtree). Base address is 0xe0000000, the same in both places.
Goal
I want to be able to capture the output of messages sent to UART. If this is done by redirecting to stdout, that's fine. If it goes through a TCP socket, that's fine too. The fault injection setup uses Python, and Qemu is running as a subprocess, so it would be easy to get the output from either one of those sources.
Note: when run in the fault injection setup, the Qemu invocation is
qemu-system-arm -M xilinx-zynq-a9 -cpu cortex-a9 -nographic -kernel $BUILD_DIR/mm.elf -m 512M -gdb tcp::3345 -S -monitor telnet::3347,server,nowait
The main differences being 1) the GDB port number is different (so multiple instances can run simultaneously) and 2) Qemu is to be controlled using a telnet connection over a socket, so it can be controlled by the Python script.
You need to initialize the UART prior to attempt outputing any characters.
The UART0 emulation is working fine for example by using a slightly modified version of this program:
/opt/qemu-4.2.0/bin/qemu-system-arm -semihosting --semihosting-config enable=on,target=native -nographic -serial mon:stdio -machine xilinx-zynq-a9 -m 768M -cpu cortex-a9 -kernel hello05.elf
Hello number 1
The output of the git diff command after modifications were made was:
diff --git a/Hello01/Makefile b/Hello01/Makefile
index 4a1b512..8d6d12a 100644
--- a/Hello01/Makefile
+++ b/Hello01/Makefile
## -1,10 +1,10 ##
ARMGNU ?= arm-linux-gnueabihf
-COPS =
+COPS = -g -O0
ARCH = -mcpu=cortex-a9 -mfpu=vfpv3
gcc : hello01.bin
-all : gcc clang
+all : gcc
clean :
rm -f *.o
## -15,8 +15,6 ## clean :
rm -f *.img
rm -f *.bc
-clang: hello02.bin
-
startup.o : startup.s
$(ARMGNU)-as $(ARCH) startup.s -o startup.o
diff --git a/Hello01/hello01.c b/Hello01/hello01.c
index 20cb4a4..14ed2a0 100644
--- a/Hello01/hello01.c
+++ b/Hello01/hello01.c
## -10,16 +10,16 ##
*/
-#define UART1_BASE 0xe0001000
-#define UART1_TxRxFIFO0 ((unsigned int *) (UART1_BASE + 0x30))
+#define UART0_BASE 0xe0000000
+#define UART0_TxRxFIFO0 ((unsigned int *) (UART0_BASE + 0x30))
-volatile unsigned int * const TxRxUART1 = UART1_TxRxFIFO0;
+volatile unsigned int * const TxRxUART0 = UART0_TxRxFIFO0;
void print_uart1(const char *s)
{
while(*s != '\0')
{ /* Loop until end of string */
- *TxRxUART1 = (unsigned int)(*s); /* Transmit char */
+ *TxRxUART0 = (unsigned int)(*s); /* Transmit char */
s++; /* Next char */
}
}
## -28,4 +28,4 ## void c_entry()
{
print_uart1("\r\nHello world!");
while(1) ; /*dont exit the program*/
-}
\ No newline at end of file
+}
diff --git a/Hello05/Makefile b/Hello05/Makefile
index 9d3ca23..bc9bb61 100644
--- a/Hello05/Makefile
+++ b/Hello05/Makefile
## -1,5 +1,5 ##
ARMGNU ?= arm-linux-gnueabihf
-COPS =
+COPS = -g -O0
ARCH = -mcpu=cortex-a9 -mfpu=vfpv3
gcc : hello05.bin
diff --git a/Hello05/hello05.c b/Hello05/hello05.c
index 1b92dde..01ce7ee 100644
--- a/Hello05/hello05.c
+++ b/Hello05/hello05.c
## -26,7 +26,7 ##
void c_entry()
{
- init_uart1_RxTx_115200_8N1();
+ init_uart0_RxTx_115200_8N1();
printf("\nHello number %d\n",1);
while(1) ; /*dont exit the program*/
}
diff --git a/Hello05/xuartps.c b/Hello05/xuartps.c
index bdf7ad1..74f68bd 100644
--- a/Hello05/xuartps.c
+++ b/Hello05/xuartps.c
## -16,42 +16,42 ##
void putc(int *p ,char c);
/*
-* Initiate UART1 ( /dev/ttyACM0 on host computer )
+* Initiate UART0 ( /dev/ttyACM0 on host computer )
* 115,200 Baud 8-bit No-Parity 1-stop-bit
*/
-void init_uart1_RxTx_115200_8N1()
+void init_uart0_RxTx_115200_8N1()
{
/* Disable the transmitter and receiver before writing to the Baud Rate Generator */
- UART1->control_reg0=0;
+ UART0->control_reg0=0;
/* Set Baudrate to 115,200 Baud */
- UART1->baud_rate_divider =XUARTPS_BDIV_CD_115200;
- UART1->baud_rate_gen= XUARTPS_BRGR_CD_115200;
+ UART0->baud_rate_divider =XUARTPS_BDIV_CD_115200;
+ UART0->baud_rate_gen= XUARTPS_BRGR_CD_115200;
/*Set 8-bit NoParity 1-StopBit*/
- UART1->mode_reg0 = XUARTPS_MR_PAR_NONE;
+ UART0->mode_reg0 = XUARTPS_MR_PAR_NONE;
/*Enable Rx & Tx*/
- UART1->control_reg0= XUARTPS_CR_TXEN | XUARTPS_CR_RXEN | XUARTPS_CR_TXRES | XUARTPS_CR_RXRES ;
+ UART0->control_reg0= XUARTPS_CR_TXEN | XUARTPS_CR_RXEN | XUARTPS_CR_TXRES | XUARTPS_CR_RXRES ;
}
-void sendUART1char(char s)
+void sendUART0char(char s)
{
/*Make sure that the uart is ready for new char's before continuing*/
- while ((( UART1->channel_sts_reg0 ) & UART_STS_TXFULL) > 0) ;
+ while ((( UART0->channel_sts_reg0 ) & UART_STS_TXFULL) > 0) ;
/* Loop until end of string */
- UART1->tx_rx_fifo= (unsigned int) s; /* Transmit char */
+ UART0->tx_rx_fifo= (unsigned int) s; /* Transmit char */
}
/* "print.h" uses this function for is's printf implementation */
void putchar(char c)
{
if(c=='\n')
- sendUART1char('\r');
- sendUART1char(c);
+ sendUART0char('\r');
+ sendUART0char(c);
}
/* <stdio.h>'s printf uses puts to send chars
## -61,9 +61,9 ## int puts(const char *s)
while(*s != '\0')
{
if(*s=='\n')
- sendUART1char('\r');
+ sendUART0char('\r');
- sendUART1char(*s); /*Send char to the UART1*/
+ sendUART0char(*s); /*Send char to the UART0*/
s++; /* Next char */
}
return 0;
diff --git a/Hello05/xuartps.h b/Hello05/xuartps.h
index fc5008f..64e3b88 100644
--- a/Hello05/xuartps.h
+++ b/Hello05/xuartps.h
## -13,7 +13,7 ##
#define u32 unsigned int
#endif
-#define UART1_BASE 0xe0001000
+#define UART0_BASE 0xe0000000
// Register Description as found in
// B.33 UART Controller (UART) p.1626
struct XUARTPS{
## -34,7 +34,7 ## struct XUARTPS{
u32 Flow_delay_reg0; /* Flow Control Delay Register def=0*/
u32 Tx_FIFO_trigger_level;}; /* Transmitter FIFO Trigger Level Register */
-static struct XUARTPS *UART1=(struct XUARTPS*) UART1_BASE;
+static struct XUARTPS *UART0=(struct XUARTPS*) UART0_BASE;
/*
Page 496
## -87,11 +87,11 ## static struct XUARTPS *UART1=(struct XUARTPS*) UART1_BASE;
#define XUARTPS_MR_CLKS_REF_CLK 0 /* 0: clock source is uart_ref_clk*/
/*
-* Initiate UART1 ( /dev/ttyACM0 on host computer )
+* Initiate UART0 ( /dev/ttyACM0 on host computer )
* 115,200 Baud 8-bit No-Parity 1-stop-bit
*/
-void init_uart1_RxTx_115200_8N1();
-void sendUART1char(char s);
+void init_uart0_RxTx_115200_8N1();
+void sendUART0char(char s);
int puts(const char *s);
//void putc((void*), char);
The command executed from the ZedBoard-BareMetal-Examples/Hello05 directory for building the modified Hello05 example was:
make ARMGNU=/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi clean all
This being said, the last comment from your previous post made me think that you may just want to be able to see the output of your program, but not necessarily by using UART0.
If this is the case, using the Angel/Semihosting interface would do the job - I understand you may have attempted to go this way.
Example:
// hello.c:
#include <stdlib.h>
int main(int argc, char** argv)
{
printf("Hello, World!\n");
return EXIT_SUCCESS;
}
gcc command:
/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc -g -O0 --specs=rdimon.specs -o hello.elf hello.c
qemu command:
/opt/qemu-4.2.0/bin/qemu-system-arm -semihosting --semihosting-config enable=on,target=native -nographic -serial mon:stdio -machine xilinx-zynq-a9 -m 768M -cpu cortex-a9 -kernel hello.elf
Outcome:
Hello, World!
Using the semihosting interface would allow you to read/write files, read user input, and to use some of the xUnit testing frameworks available for either C or C++ - I have been for example successfully be using CppUnit with QEMU and the Semihosting interface. at several occasions.
I hope this help.

Missing Symbol during Runtime in Over-The-Air Programming Code

I am currently working on developing over-the-air programming support on sky motes. Attached are the files that I have so far. I am basically trying to use the sky-shell-exec example to load my modified test-deluge.ce file onto the mote. I then try to run the test-deluge file using the shell 'exec' command as done in the sky-shell-exec example.
The final goal is to load both the test-deluge.ce and hello-world.ce compiled files onto the mote and then be able to 'exec' my test-deluge.ce file which would then find the stored hello-world.ce file and do a deluge_disseminate on it.
The progression of command I am running are as follows:
1) sudo make TARGET=sky clean CLEAN=symbols.?
2) sudo make sky-shell-exec.sky TARGET=sky
3) sudo make sky-shell-exec.sky CORE=sky-shell-exec.sky TARGET=sky
4) sudo make sky-shell-exec.upload CORE=sky-shell-exec.sky
5) sudo make compile-test-deluge-executable
6) sudo make upload-test-deluge-executable
7) sudo make login
8) ls (to see that the file made it)
9) exec test-deluge.ce
At this point I get a 'Symbol not found: deluge_disseminate' error
I believe the error is in the 'CORE=...' part of the make (in step 2 above). I have inspected the symbols.c file that is filled out in step 2 of the above and indeed there is no symbol for deluge_disseminate or any of the deluge commands for that matter that I recall.
For experimentation I tried the following:
sudo make test-deluge.sky TARGET=sky
sudo make test-deluge.sky CORE=test-deluge.sky TARGET=sky
and I find that the symbols for deluge are there, but I can't proceed to properly make sky-shell-exec file since doing so erases the symbols table and writes a new one.
I feel like there must be a simple fix to this as I can run hello-world from the sky-shell-exec example directory after following the above steps (1-9).
Does anyone have an idea of how to go about this?
NOTE: There may be a bug in my test-deluge.c where I try to open 'hello-world.sky' instead of 'hello-world.ce'...I wasn't really sure which one. I haven't been able to test this yet because of the missing symbol issue explained above, but if anyone would be willing to shed light on this issue as well I would be very appreciative.
Thanks
MAKEFILE
CONTIKI = ../..
ifndef TARGET
TARGET=sky
endif
APPS = deluge serial-shell
all: blink sky-collect #rt-leds test-button test-cfs tcprudolph0
#all: $(CONTIKI_PROJECT)
%.tgz: %.ihex
mkdir $(basename $<) ; \
mv $< $(basename $<) ; \
echo $(basename $<)/$(basename $<).ihex 600 > $(basename $<)/runfile ; \
tar czf $# $(basename $<)
%.class: %.java
javac $(basename $<).java
viewrssi: ViewRSSI.class
make login | java ViewRSSI
include $(CONTIKI)/Makefile.include
%.shell-upload: %.ce
(echo; sleep 4; echo "~K"; sleep 4; \
echo "dec64 | write $*.ce | null"; sleep 4; \
../../tools/base64-encode < $<; sleep 4; \
echo ""; echo "~K"; echo "read $*.ce | size"; sleep 4) | make login
.PHONY: compile-test-deluge-executable upload-test-deluge-executable compile-hello-world-executable upload-test-deluge-executable
compile-hello-world-executable: hello-world.ce
echo Compiled Contiki executable: $<
upload-hello-world-executable: hello-world.shell-upload
echo Uploaded Contiki executable: $<
compile-test-deluge-executable: test-deluge.ce
echo Compiled Contiki executable: $<
upload-test-deluge-executable: test-deluge.shell-upload
echo Uploaded Contiki executable: $<
sky-shell-exec.c
#include "contiki.h"
#include "shell.h"
#include "serial-shell.h"
#include "deluge.h"
#include "dev/watchdog.h"
#include "net/rime.h"
#include "dev/cc2420.h"
#include "dev/leds.h"
#include "dev/light.h"
#include "dev/sht11.h"
#include "dev/battery-sensor.h"
#include "lib/checkpoint.h"
#include "net/rime/timesynch.h"
#include <stdio.h>
#include <string.h>
int (*keep_1)(void) = deluge_disseminate;
int (*keep_2)(void) = node_id_burn;
/*---------------------------------------------------------------------------*/
PROCESS(sky_shell_process, "Sky Contiki shell");
AUTOSTART_PROCESSES(&sky_shell_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(sky_shell_process, ev, data)
{
PROCESS_BEGIN();
serial_shell_init();
/*shell_blink_init();*/
shell_file_init();
shell_coffee_init();
/*shell_ps_init();*/
/*shell_reboot_init();*/
/*shell_rime_init();*/
/*shell_rime_netcmd_init();*/
/*shell_rime_ping_init();*/
/*shell_rime_debug_init();*/
/*shell_rime_sniff_init();*/
/*shell_sky_init();*/
shell_text_init();
/*shell_time_init();*/
/* shell_checkpoint_init();*/
shell_exec_init();
shell_base64_init();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
test-deluge.c
#include "contiki.h"
#include "cfs/cfs.h"
#include "deluge.h"
#include "sys/node-id.h"
#include "loader/elfloader.h"
#include <stdio.h>
#include <string.h>
#ifndef SINK_ID
#define SINK_ID 1
#endif
#ifndef FILE_SIZE
#define FILE_SIZE 1000
#endif
PROCESS(deluge_test_process, "Deluge test process");
AUTOSTART_PROCESSES(&deluge_test_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(deluge_test_process, ev, data)
{
static struct etimer et;
node_id_burn(2);
PROCESS_BEGIN();
if(node_id == SINK_ID) {
printf("Sink node: trying to transmit file.\n");
} else {
printf("Non-sink node: trying to recieve file.\n");
}
cfs_remove("hello-world.sky");
int fd = cfs_open("hello-world.sky", CFS_WRITE | CFS_READ);
if(fd < 0) {
process_exit(NULL);
}
#if 0
if(cfs_seek(fd, FILE_SIZE, CFS_SEEK_SET) != FILE_SIZE) {
printf("failed to seek to the end\n");
}
#endif
deluge_disseminate("hello-world.sky", node_id == SINK_ID);
cfs_close(fd);
etimer_set(&et, CLOCK_SECOND * 5);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
if(node_id != SINK_ID) {
fd = cfs_open("hello-world.sky", CFS_READ);
if(fd < 0) {
printf("failed to open the test file\n");
} else {
printf("Start dynamic loading\n");
int ret = elfloader_load(fd);
printf("%d\n", ret);
cfs_close(fd);
int i;
switch(ret) {
case ELFLOADER_OK:
for(i=0; elfloader_autostart_processes[i] != NULL; i++) {
printf("exec: starting process %s. \n",
elfloader_autostart_processes[i]->name);
}
autostart_start(elfloader_autostart_processes);
break;
default:
printf("Unkown return code from ELF loader (internal bug)\n");
break;
}
}
}
etimer_reset(&et);
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
hello-world.c
#include "contiki.h"
#include <stdio.h> /* For printf() */
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
printf("Hello, world\n");
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
So with great help from the contiki community I was able to gather the following solution:
"Hi,
The problem is that the build system of Contiki tries to "act smart"
and excludes symbols the application apparently does not need. So in
this case the deluge_disseminate function code is optimized away from
sky-shell-exec executable. Obviously, this conflicts with the basic
intuitions that the programmer has in case of over-the-air
programming.
To work around this issue, add a reference to deluge_disseminate in
sky-shell-exec code. For example, add this line (at global scope):
int (*keep)(void) = deluge_disseminate;
You can also try to tweak GCC linker options or use a custom linker script."
Using the same trick for node_id_burn as well, test-deluge.c runs.
The corrections have been made to the above code.
Hopefully this helps anyone else out there who may be struggling with OTA code in Contiki.

Resources