atmega: register data gets corrupted by division operation - cpu-registers

Hello I'm writing in C with an olimexino (arduino). I'm using the following code to load 2 registers (atmega328):
asm (
"ldi r20, 0 \n" //load register r20 with 0
"ldi r21, 16 \n" //load register r21 with 16
: : : "r20","r21" //compiler directive to reserve the two registers );
then I use this:
asm ( "out 0x05, r21 \n" ); //write '0' to portB
asm ( "out 0x05, r20 \n" ); //write '10000' to portB
to write from the two registers to port B. But using the two registers r20 and r21 creates a problem. A conflict occurs if i do a division operation. for example, if any part of my program has a statement like "x = x/6" or "y=x%9" then the numbers i stored in those registers seem to change. if i do a simple division like "x/4" or "x%8" there's no problem. but any operation that's more complex than a simple shift division screws me up.
Any help? Thanks

Do it as a single, multi-line statement:
asm (
"ldi r20, 0 \n" //load register r20 with 0
"ldi r21, 16 \n" //load register r21 with 16
"out 0x05, r21 \n" //write '0' to portB
"out 0x05, r20 \n" //write '10000' to portB
: : : "r20","r21" //compiler directive to reserve the two registers );
Or perhaps even better:
asm (
"out %0, %1 \n"
"out %0, %2 \n"
: : "i"(5), "r"(16), "r"(0));
Or how about a routine:
void WriteToPort5(unsigned char b)
{
asm ("out 0x05, %0"
: : "r"(b));
}
That you can call like this:
WriteToPort5(16);
WriteToPort5(0);

Related

Bootloader Jump Function. How to Jump to the right Address?

I am trying to create a bootloader that jumps to my application code on a MKE02Z32VFM4 (KEO2 Series from Freescale). I am working with the Keil IDE 5 and the Armv6 Compiler v6.16.
After Issuing the Jump Instruction to the application start address, the code Jumps to "a" reset handler. And when the instruction to jump to __main is reached, it jumps to the main of the bootloader. The Flash Memory is defined by the linker file as followed:
#define m_interrupts_start 0x00000000
#define m_interrupts_size 0x00000200
#define m_flash_config_start 0x00000400
#define m_flash_config_size 0x00000010
#define bootloader_start 0x00000410
#define bootloader_size 0x00000800 //2kb size 0x410+0x800=0xC10 ==> 256 byte aligned => 0xE00
#define ota_part_0_start 0x00000E00 //Vector Table interrupt must be 256 byte aligned
#define ota_part_0_size 0x00003800 //14KB (14336 Byte) 0xE00+0x3800 => 0x4600
#define ota_part_1_start 0x00004600
#define ota_part_1_size 0x00003800 //14KB (14336 Byte) 0x4600+0x3800 = 0x7E00 || flash_end == 0x0000 7FFF => 0x100(256) byte frei
#define m_data_start 0x1FFFFC00 //ram start
#define m_data_size 0x00001000 //4kb
The application linker file (scatter file) is working with these defines:
#define m_interrupts_start 0x00000E00 //Address of the application reset handler
#define m_interrupts_size 0x00000200
#define m_flash_config_start 0x00001000 //some config bytes, defined by manufacturer
#define m_flash_config_size 0x00000010
#define m_text_start 0x00001010 // start address of application code
#define m_text_size 0x000035F0
#define m_data_start 0x1FFFFC00 //ram start
#define m_data_size 0x00001000 //4kb
The reset handler is written in assembler, i tried to comment the instructions:
Reset_Handler:
cpsid i /* Mask interrupts */
.equ VTOR, 0xE000ED08 //.equ is like #define in C. VTOR = predefined ARMv6 label. 0xE000ED08 VectorTableOffsetRegister.
ldr r0, =VTOR // load word from memory. load value from word at VTOR address to r0. R0 now contains the offset for the vector table.
ldr r1, =__Vectors // load word from memory. load value of word at __Vectors address to r1. --> the first word at __Vectors is the initial stack pointer
str r1, [r0] //store Register to memory. content of r1 is stored to memory adress in r0(==VTOR) --> initial stack pointer is stored to the first word of the Vector table
ldr r2, [r1] //load word from memory. r2 is set to the value of the word in memory at address in r1. --> r2 is set to the address of the initial stack pointer
msr msp, r2 //move to special register. move value of r2 to special register msp (main stack pointer) --> main stack pointer is set to the valjue of the initial stack pointer
ldr r0,=SystemInit //set register 0 to address of SystemInit function. (
blx r0 // branch with link ( to address of r0)
cpsie i /* Unmask interrupts */
ldr r0,=__main
bx r0
.pool
.size Reset_Handler, . - Reset_Handler
The bootloader code is as followed:
Address in this first test is the value 0x00000E00 (start of user app)
__attribute__( ( naked, noreturn ) ) void BootJumpASM( uint32_t SP, uint32_t RH )
{
__asm("MSR MSP,r0");
__asm("BX r1");
}
static void BootJump( uint32_t *Address )
{
if( CONTROL_nPRIV_Msk & __get_CONTROL( ) ) //THIS is from the arm doku, but it is always false in our implementation and skipped.
{ /* not in privileged mode */
EnablePrivilegedMode( ) ;
}
NVIC->ICER[0] = 0xFFFFFFFF ;
NVIC->ICPR[0] = 0xFFFFFFFF ;
SysTick->CTRL = 0 ;
SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk ;
if( CONTROL_SPSEL_Msk & __get_CONTROL( ) ) //THIS is from the arm doku, but it is always false in our implementation and skipped. (only 1 stack pointer used)
{ /* MSP is not active */
__set_MSP( __get_PSP( ) ) ;
__set_CONTROL( __get_CONTROL( ) & ~CONTROL_SPSEL_Msk ) ;
}
SCB->VTOR = ( uint32_t )Address ; //Setting the Vector Table Offset Register to the start of the user app.
BootJumpASM( Address[ 0 ], Address[ 1 ] ) ; //This function is taken from the Arm Documentation
}
After
SCB->VTOR = (uint32_t)Address; // Set VTOR to 0xE00
The VTOR register IS updated to 0xE00. However after executing the function:
__attribute__( ( naked, noreturn ) ) void BootJumpASM( uint32_t SP, uint32_t RH )
{
__asm("MSR MSP,r0");
__asm("BX r1"); //<-- This is the Point where VTOR changes it value to 0x00 again
}
VTOR is 0x00 again and im in the resethandler. This resethandler connects to the bootloader main. So i assume im in the reset handler at 0x00 and not the one at 0xE00. I checked the flash memory and am positive that a Vector Table is located at 0x000 AND 0xE00. I am positive that the firmware of the application is also at the right place in the flash.
I am assuming that I either:
Defined the Memory space wrong.
The BootJumpASM function jumps to a illegal location and the MCU restarts over at 0x00 with a reset VTOR Register.
I am not sure, why the BootJumpASM function uses r0 and r1 and what it does with the arguments of the function. I am simply new at assembler and all the specific compiler attributes. The function like described above is directly copied from:
https://developer.arm.com/documentation/ka002218/latest
And while i do not understand how the compiler manages to put the Function arguments to register r0 and r1 I am sure that the mistake is at my side and not in the official arm docs.
Can someone explain to me, why after the second instruction of the "BootJumpASM" function "VTOR" is reset to 0x00?
and why the resethandler ,the debugger is in right after, connects to the bootloader main and not the application main. And how do i manage to jump to the right location in memory.
Thanks for your time. I hope this explanation is not too confusing.
The problem was not the jump instruction, but the Debugger of the Keil IDE. I set up the debug environment according to arm and Keil documentation but after the jump out of the code environment of the bootloader into the application memory area, the Debugger triggered a reset. (Bootloader is a seperate Keil project.)
Starting the debugger within the application project, no such reset is triggered after the jump instruction and following the dissasembly view the bootloader executes as expected and the jump instruction works.
Thanks to all for taking time to try and find the error with me.

ADS 1015 Sampling Rate

I recently got an ADS 1015 (in order to make high frequency measurement of a voltage accros a capacitor). The datasheet specified 3.3 kSPS (Sample per seconds). However I only get around 500SPS maximum.
And after looking all around, I've found several ressources which talked about a register override... However, I'm not an expert in this field and need your help!
Here is the code I use to test the sampling rate (using an Arduino nano, arduino code is a C++ variant):
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <SPI.h>
Adafruit_ADS1015 ADS_0(0x48);
int i = 0;
long results = 0;
void setup(void)
{
Serial.begin(9600);
// CODE FOUND ON THE INTERNET BUT REJECT ERROR BC OF readRegister function not defined... However, I haven't found any library missing... Strange ---------------
const uint8_t adcAddress = 0x48;
const uint8_t configRegister = 0x01;
uint16_t configValue = readRegister( adcAddress, configRegister );
Serial.print( "read config value 0x" );
Serial.println( configValue, HEX );
configValue = ( configValue & !ADS1015_REG_CONFIG_DR_MASK) | ADS1015_REG_CONFIG_DR_3300SPS;
writeRegister( adcAddress, configRegister, configValue );
Serial.print( "sent config value 0x" );
Serial.println( configValue, HEX );
configValue = readRegister( adcAddress, configRegister );
Serial.print( "verifying by rereading config value 0x" );
Serial.println( configValue, HEX );
// -------------------------------------------------------------
ads1015.begin();
}
void loop(void)
{
int i=0;
long depart = micros();
while(i != 1000) {
i++;
results = ads1015.readADC_SingleEnded(0);
}
Serial.println(micros() - depart);
}
This code return about 2,000,000 which correspond to 2 sec or 500 Hz sampling rate...
Thanks in advance,
~TBD
According to the datasheet I think you have to first set MODE to 0 (Continuous-conversion mode) and DR to 0b111 in the Config Register (pg 24).
Then you can probably use an ISR on ALERT/RDY pin (after proper configuration - pg 15) and read the data each time the interrupt is triggered.
Page 15:
The ALERT/RDY pin can also be configured as a conversion ready pin.
Set the most-significant bit of the Hi_thresh register to 1 and the
most-significant bit of Lo_thresh register to 0 to enable the pin as a
conversion ready pin.

How to speed update time of IDR Register STM32?

I have a question about the IDR Register of STM32
I set the pin0 of the ODR Register to 1 in my code below and I want to check, if the pin0 in the IDR register is set to 1. The problem is, after setting the pin to 1, I must wait 1 second until the pin in the IDR register is set to 1.
How can I read the pin state without waiting?
How can I solve this problem?
void init_pins(void)
{
GPIOG->OTYPER |= (0x01 << 0); // Pin 0 as open drain
GPIOG->OTYPER &= ~(0x01 << 1); // Pin 1 as push - pull
GPIOG->BSRRL = 0x01 << 1; // Pin 1 to High
GPIOG->BSRRL = 0x01 << 0; // Pin 0 to High
microsecond_Delay(1000000);
if( !(GPIOG->IDR & 0x01) )
{
errorCode = -1 ; //Error Code for Bus not floating
}
}
Use CMSIS header files provided by the STM.
If configure pin as open drain you can't set it HIGH. It has to be done by the external pull-up. Your configuration is just wrong. If you do not have external pull-up (or at leat the internal one) the state of the pin if you do not set it to zero is unpredictable.

Writing ttyUSB snooper failing

Summary: I am writing a ttyUSB snooper. The code is supposed to read(2) data from a serial port and write(2) it over to another serial port. Reading from the serial port works great with /bin/cat but fails with my code.
Hardware Setup is: I made an FTDI cross-over cable, and put one end in the Windows XP machine as Com2 and the other end in a modern Linux machine as /dev/ttyUSB0. The Linux machine has a USB to Serial cable that shows up as /dev/ttyUSB1. It is connected to the actual hardware unit I am trying to snoop. I verified, the hardware works great.
This part works: I will "cat /dev/ttyUSB0 > /tmp/data" and then have the WinXP machine issue the "read from the device over Com2", and the following six (6) bytes data will be sent over.
\x02\x01\x40\x00\x0a\x9e
This "packet" is sent 4 times or so with a very slight delay, this appears to be the WinXP code just trying a few times. If I replay this just once, it works.
If I simply do "cat /tmp/data > /dev/ttyUSB1", the hardware device will respond properly suggesting that it received the command. Great!
Problem and My Code: I am writing some code to be run on the Linux machine that will read(2) from /dev/ttyUSB0 and write it over to /dev/ttyUSB1 and vice versa. However, for some unknown reason it will only receive 4 bytes in the first "packet", then 5 in the subsequent 3 attempts. Sometimes, the 5 bytes appear slightly "damaged", meaning I see \xffffff for the last or second to last byte. Here is my code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <strings.h>
void hexdump(char *data, int size) {
for (size_t i = 0; i < size; ++i)
printf("%02x ", data[i]);
putchar('\n');
}
int main() {
int fdzero;
int fdone;
int maxfd;
fd_set sockrd;
struct timeval timer;
char data[10];
int size;
char tmp;
fdzero = open("/dev/ttyUSB0", O_RDWR);
if (fdzero == -1) {
perror("Failed to open /dev/ttyUSB0");
return 1;
}
fdone = open("/dev/ttyUSB1", O_RDWR);
if (fdone == -1) {
perror("Failed to open /dev/ttyUSB1");
return 1;
}
if (fdzero > fdone)
maxfd = fdzero;
else
maxfd = fdone;
printf("Enter loop\n");
for(;;) {
bzero(data, 10);
// fflush(NULL);
FD_ZERO(&sockrd);
FD_SET(fdzero, &sockrd);
FD_SET(fdone, &sockrd);
timer.tv_sec = 60;
timer.tv_usec = 0;
select(maxfd+1, &sockrd, NULL, NULL, &timer);
if (FD_ISSET(fdzero, &sockrd)) {
size = read(fdzero, data, 10);
if (size == -1) {
perror("Failed to read /dev/ttyUSB0");
break;
}
size = write(fdone, data, size);
if (size == -1) {
perror("Failed to write to /dev/ttyUSB1");
break;
}
printf("ttyUSB0 -> ttyUSB1: %d\n", size);
}
// This portion does not trigger yet, but its a mirror
// Yes, I know...bad code :(
else {
size = read(fdone, data, 10);
if (size == -1) {
perror("Failed to read /dev/ttyUSB1");
break;
}
size = write(fdzero, data, size);
if (size == -1) {
perror("Failed to write to /dev/ttyUSB0");
break;
}
printf("ttyUSB1 -> ttyUSB0: %d\n", size);
}
// Used to monitor what is read()/write()
hexdump(data, size);
}
return 0;
}
When I actually run this code, I see this:
# cc snoop.c -o snoop
# ./snoop
Enter loop
ttyUSB0 -> ttyUSB1: 4
02 00 40 ffffff9e
ttyUSB0 -> ttyUSB1: 4
02 00 40 ffffff9e
ttyUSB0 -> ttyUSB1: 4
02 00 40 ffffff9e
ttyUSB0 -> ttyUSB1: 5
01 02 00 40 ffffff9e
ttyUSB0 -> ttyUSB1: 5
01 02 00 40 ffffff9e
ttyUSB0 -> ttyUSB1: 5
01 02 00 40 ffffff9e
Notice that only 4 or 5 bytes are being received and subsequently sent over at any given time. Not 6. Also, notice that the "packet" is distorted. What in the world would cause that???
Rationality if you're interested: I have old software that ONLY runs on Windows XP and will NOT work in a VM (this is a known issue). I would love to capture the traffic going over the serial port. I purchased a WinXP machine just to do this.
Okay, so your two questions here:
Sometimes, the 5 bytes appear slightly "damaged", meaning I see \xffffff for the last or second to last byte.
This is because of how printf interprets the data coming in(this may be of interest). It is being passed in as a char, which is signed. The high-order bits are being interpreted in this case. To fix this part, your hexdump(char* data, int len) should be either hexdump(unsigned char* data, int len) or use a byte-sized type such as uint8_t, so that your signature looks like hexdump(uint8_t* data, int len).
However, for some unknown reason it will only receive 4 bytes in the first "packet", then 5 in the subsequent 3 attempts.
This is almost certainly due to the fact that you do not set any settings on the serial port. One of the characters that you have is 0x0A, which is the linefeed character. This is either being ignored by the serial port driver, or translated into a different character all together. To fix this, you must set the serial port settings to be raw and not translate any characters that come in. I generally do something like the following:
struct termios newio;
if( tcgetattr( fd, &newio ) < 0 ){ /* error handling here */ }
/* Set some default settings */
newio.c_iflag |= IGNBRK;
newio.c_iflag &= ~BRKINT;
newio.c_iflag &= ~ICRNL;
newio.c_oflag = 0;
newio.c_lflag = 0;
newio.c_cc[VTIME] = 0;
newio.c_cc[VMIN] = 1;
/* Set our baud rate */
cfsetospeed( &newio, B9600 );
cfsetispeed( &newio, B9600 );
/* Character size = 8 */
newio.c_cflag &= ~CSIZE;
newio.c_cflag |= CS8;
/* One stop bit */
newio.c_cflag &= ~CSTOPB;
/* Parity = none */
newio.c_iflag &= ~IGNPAR;
newio.c_cflag &= ~( PARODD | PARENB );
newio.c_iflag |= IGNPAR;
/* No flow control */
newio.c_iflag &= ~( IXON | IXOFF | IXANY );
/* Set our serial port settings */
if( tcsetattr( fd, TCSANOW, &newio ) < 0 ) { /* error handling code here */ }
If you don't want to set the serial port settings this way, I've written a small library which should abstract the small details out for you.

mpirun with multiple executables, reset rank numbers per executable [duplicate]

I have two openmpi programs which I start like this
mpirun -n 4 ./prog1 : -n 2 ./prog2
Now how do I use MPI_Comm_size(MPI_COMM_WORLD, &size) such that i get size values as
prog1 size=4
prog2 size=2.
As of now I get "6" in both programs.
This is doable albeit a bit cumbersome to get that. The principle is to split MPI_COMM_WORLD into communicators based on the value of argv[0], which contains the executable's name.
That could be something like that:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <mpi.h>
int main( int argc, char *argv[] ) {
MPI_Init( &argc, &argv );
int wRank, wSize;
MPI_Comm_rank( MPI_COMM_WORLD, &wRank );
MPI_Comm_size( MPI_COMM_WORLD, &wSize );
int myLen = strlen( argv[0] ) + 1;
int maxLen;
// Gathering the maximum length of the executable' name
MPI_Allreduce( &myLen, &maxLen, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD );
// Allocating memory for all of them
char *names = malloc( wSize * maxLen );
// and copying my name at its place in the array
strcpy( names + ( wRank * maxLen ), argv[0] );
// Now collecting all executable' names
MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
names, maxLen, MPI_CHAR, MPI_COMM_WORLD );
// With that, I can sort-out who is executing the same binary as me
int binIdx = 0;
while( strcmp( argv[0], names + binIdx * maxLen ) != 0 ) {
binIdx++;
}
free( names );
// Now, all processes with the same binIdx value are running the same binary
// I can split MPI_COMM_WORLD accordingly
MPI_Comm binComm;
MPI_Comm_split( MPI_COMM_WORLD, binIdx, wRank, &binComm );
int bRank, bSize;
MPI_Comm_rank( binComm, &bRank );
MPI_Comm_size( binComm, &bSize );
printf( "Hello from process WORLD %d/%d running %d/%d %s binary\n",
wRank, wSize, bRank, bSize, argv[0] );
MPI_Comm_free( &binComm );
MPI_Finalize();
return 0;
}
On my machine, I compiled and ran it as follow:
~> mpicc mpmd.c
~> cp a.out b.out
~> mpirun -n 3 ./a.out : -n 2 ./b.out
Hello from process WORLD 0/5 running 0/3 ./a.out binary
Hello from process WORLD 1/5 running 1/3 ./a.out binary
Hello from process WORLD 4/5 running 1/2 ./b.out binary
Hello from process WORLD 2/5 running 2/3 ./a.out binary
Hello from process WORLD 3/5 running 0/2 ./b.out binary
Ideally, this could be greatly simplified by using MPI_Comm_split_type() if the corresponding type for sorting out by binaries existed. Unfortunately, there is no such MPI_COMM_TYPE_ pre-defined in the 3.1 MPI standard. The only pre-defined one is MPI_COMM_TYPE_SHARED to sort-out between processes running on the same shared memory compute nodes... Too bad! Maybe something to consider for the next version of the standard?
I know the question is outdated but I wanted to add to the answer by Hristo Lliev to make it work not just for OpenMPI:
you can use the value of an MPI parameter MPI_APPNUM which will be different for each executable as "color" and split the MPI_COMM_WORLD into separate communicators, then print the size of those sub-communicators. Use MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_APPNUM, &val, &flag ); to get the value of MPI_APPNUM.
Since you are using Open MPI, there is a very simple OMPI-specific solution:
#include <stdlib.h>
MPI_Comm appcomm;
int app_id = atoi(getenv("OMPI_MCA_orte_app_num"));
MPI_Comm_split(MPI_COMM_WORLD, app_id, 0, &appcomm);
There will be now as many different appcomm communicators as there are application contexts.

Resources