Strange behaviour of STM32F407 while writhing to CAN_BTR register - cpu-registers

I defined following user type:
typedef struct
{
union
{
struct
{
uint32_t BRP :10;
uint32_t Reserved_1 :6;
uint32_t TS1 :4;
uint32_t TS2 :3;
uint32_t Reserved_2 :1;
uint32_t SJW :2;
uint32_t Reserved_3 :4;
uint32_t LBKM :1;
uint32_t SILM :1;
};
uint32_t reg;
};
}__attribute__((packed, aligned(1))) _CAN_BTR;
Then created variable:
_CAN_BTR *CAN_BTR = (_CAN_BTR*) &(CAN->BTR);
But when wrighting with following code i get wrong results:
CAN_BTR->TS1 = 9;
CAN_BTR->TS2 = 4;
CAN_BTR->BRP = 6;
CAN_BTR->SJW = 3;
At the end it seems like problem in the wrighting to register, because everithing is fine until
strb r3, [r2, #2]
where r3 hold correct value r2 holds base address of CAN_BTR register and #2 ossfet pionts to third byte of register which holds TS1 value.
After some experiments with asm i figureg out that for some reason
strb r3, [r2, #2]
always modifyes first (offset 0) and third (offset 2) byte of that register. With local varible there is no such problem.
CAN_BTR default value is 0x1230000 and aftar any of following instructons
strb r3, [r2, #0]
strb r3, [r2, #1]
strb r3, [r2, #2]
strb r3, [r2, #3]
it became 0x1290129.
Is there any hardware bug or restriction which i dont know of? I checked out errata for STM32F407 but there nothing about something similar in CAN section.
Thanks in advance for answers.
*UPDATE
There is more about code - disassembly listnig:
79 CAN_BTR->TS1 = 9;
080006da: ldr r2, [r7, #16]
080006dc: ldrb r3, [r2, #2]
080006de: movs r1, #9
080006e0: bfi r3, r1, #0, #4
080006e4: strb r3, [r2, #2]
80 CAN_BTR->TS2 = 4;
080006e6: ldr r2, [r7, #16]
080006e8: ldrb r3, [r2, #2]
080006ea: movs r1, #4
080006ec: bfi r3, r1, #4, #3
080006f0: strb r3, [r2, #2]
81 CAN_BTR->BRP = 6;
080006f2: ldr r3, [r7, #16]
080006f4: movs r2, #0
080006f6: orr.w r2, r2, #6
080006fa: strb r2, [r3, #0]
080006fc: ldrb r2, [r3, #1]
080006fe: bic.w r2, r2, #3
08000702: strb r2, [r3, #1]
82 CAN_BTR->SJW = 3;
08000704: ldr r2, [r7, #16]
08000706: ldrb r3, [r2, #3]
08000708: orr.w r3, r3, #3
0800070c: strb r3, [r2, #3]
Before first line register have default value 0x1230000.
After this line
080006e4: strb r3, [r2, #2]
register value is 0x1290129.
Is there any more code i need to show to illustrate my problem?
*UPDATE 2
Now type defined as:
typedef struct
{
union
{
struct
{
uint32_t BRP :10;
uint32_t :6;
uint32_t TS1 :4;
uint32_t TS2 :3;
uint32_t :1;
uint32_t SJW :2;
uint32_t :4;
uint32_t LBKM :1;
uint32_t SILM :1;
};
uint32_t reg;
};
} _CAN_BTR;
but this lead to identical asm code:
86 CAN_BTR->TS1 = 9;
08000718: ldr r2, [r7, #16]
0800071a: ldrb r3, [r2, #2]
0800071c: movs r1, #9
0800071e: bfi r3, r1, #0, #4
08000722: strb r3, [r2, #2]
*SOULTION
As pionetd out by 0___________ problem was in accessing CAN register as bytes, but reference manual permits only word(32bit) acess. Thanks!

The CAN registers HAVE to be accessed as words. Your code is accessing them as bytes, which is INVALID
Do not introduce pointers as it has a performance penalty.
}__attribute__((packed, aligned(1))) _CAN_BTR; alignment makes no sense. Packing is not needed and will emit very inefficient code and also forces byte access which is invalid!!!
You do not need to name bitfield padding.
typedef struct
{
union
{
struct
{
uint32_t BRP :10;
uint32_t :6;
uint32_t TS1 :4;
uint32_t TS2 :3;
uint32_t :1;
uint32_t SJW :2;
uint32_t :4;
uint32_t LBKM :1;
uint32_t SILM :1;
};
uint32_t reg;
};
}_CAN_BTR;
#define MYCAN_BTR ((volatile _CAN_BTR *)(&CAN -> BTR))
and access bitfields without introducing any overhead.
MYCAN_BTR -> SJW = ....
UPDATE If your compiler generates this code you need to do it different way.
#define MODIFY_CAN_BTR(field,val) do{_CAN_BTR btr = CAN->BTR; btr -> field = val; CAN -> BTR = btr -> reg;}while(0)

Related

Array of pointers, VirtualAlloc and RtlMoveMemory. MASM, some kind of problem

Does anybody know how to fix the addElement function so it ends up as another element in the array. The idea is a dynamic array, where arrayPtr is a pointer to the first element, then new elements can be added dynamically and kept track of by increasing the arrayPtr value. So in-fact I think what it would end up being is an array of pointers to DbRecord structs in memory. Allocated by VirtualAlloc and copied by RtlMoveMemory. I am kinda of hung up on RtlMoveMemeory line. I feel like my line of thinking is correct.
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
addElement PROTO: ptr DbRecord
.data?
DbRecord struct
Id dd ?
WordOne db 32 dup(?) ; db is define byte, set value of byte
WordTwo db 32 dup(?)
WordThree db 32 dup(?)
Year dd ?
DbRecord ends
arrayPtr dd ? ; pointer in memory to start of array
newElementPointer DbRecord <>
hStdOut dd ?
bytesWritten dd ?
.data
arrayCount dd 0
hello db 'Hello World!', 0
.code
main proc
LOCAL DbRecord01:DbRecord
mov [DbRecord01.Id], 1;
; any other way than one character at a time?
mov byte ptr [DbRecord01.WordOne], 'D'
mov byte ptr [DbRecord01.WordOne + 1], 'o'
mov byte ptr [DbRecord01.WordOne + 2], 'g'
mov byte ptr [DbRecord01.WordOne + 3], 0
mov byte ptr [DbRecord01.WordTwo], 'C'
mov byte ptr [DbRecord01.WordTwo + 1], 'a'
mov byte ptr [DbRecord01.WordTwo + 2], 't'
mov byte ptr [DbRecord01.WordTwo + 3], 0
mov byte ptr [DbRecord01.WordThree], 'E'
mov byte ptr [DbRecord01.WordThree + 1], 'y'
mov byte ptr [DbRecord01.WordThree + 2], 'e'
mov byte ptr [DbRecord01.WordThree + 3], 0
mov [DbRecord01.Year], 2022;
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov [hStdOut], eax
invoke WriteConsole, hStdOut, offset hello, sizeof hello, offset bytesWritten, NULL
invoke addElement, addr DbRecord01
ret
main endp
addElement proc DbRecordPointer: ptr DbRecord
invoke VirtualAlloc, NULL, sizeof DbRecord, MEM_COMMIT, PAGE_READWRITE ; I beleive store a memory address in eax
invoke RtlMoveMemory, DbRecord ptr [eax], DbRecordPointer, sizeof DbRecord ; but how to use that memory address here?
ret
addElement endp
end main
EDIT/Update:
So yes part of the answer is just passing in eax.
I am here now
How do I get the value of eax ("memory location from VirtualAlloc",) where data was copied into arrayPtr (arrayPtr + count * sizeof DbRecord)
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
addElement PROTO: ptr DbRecord
.data?
DbRecord struct
Id dd ?
WordOne db 32 dup(?) ; db is define byte, set value of byte
WordTwo db 32 dup(?)
WordThree db 32 dup(?)
Year dd ?
DbRecord ends
arrayPtr dword ? ; pointer in memory to start of array
; newElementPointer DbRecord <>
hStdOut dd ?
bytesWritten dd ?
.data
arrayCount dd 0
hello db 'Hello World!', 0
.code
main proc
LOCAL DbRecord01:DbRecord
mov [DbRecord01.Id], 1;
; any other way than one character at a time?
mov byte ptr [DbRecord01.WordOne], 'D'
mov byte ptr [DbRecord01.WordOne + 1], 'o'
mov byte ptr [DbRecord01.WordOne + 2], 'g'
mov byte ptr [DbRecord01.WordOne + 3], 0
mov byte ptr [DbRecord01.WordTwo], 'C'
mov byte ptr [DbRecord01.WordTwo + 1], 'a'
mov byte ptr [DbRecord01.WordTwo + 2], 't'
mov byte ptr [DbRecord01.WordTwo + 3], 0
mov byte ptr [DbRecord01.WordThree], 'E'
mov byte ptr [DbRecord01.WordThree + 1], 'y'
mov byte ptr [DbRecord01.WordThree + 2], 'e'
mov byte ptr [DbRecord01.WordThree + 3], 0
mov [DbRecord01.Year], 2022;
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov [hStdOut], eax
invoke WriteConsole, hStdOut, offset hello, sizeof hello, offset bytesWritten, NULL
invoke addElement, addr DbRecord01
ret
main endp
addElement proc uses edx DbRecordPointer: ptr DbRecord
Local newElementPointer: Dword
invoke VirtualAlloc, NULL, sizeof DbRecord, MEM_COMMIT, PAGE_READWRITE ; I beleive store a memory address in eax
mov newElementPointer, eax
;invoke RtlMoveMemory, newElementPointer , DbRecordPointer, sizeof DbRecord ; but how to use that memory address here?
invoke RtlMoveMemory, eax , DbRecordPointer, sizeof DbRecord
mov edx, arrayCount
inc edx
mov arrayCount, edx
;mov dword ptr [arrayPtr+arrayCount], eax
ret
addElement endp
end main

Returning a value pointed to by a pointer in x86 NASM

I'm trying to write a function in x86 NASM assembly that takes a pointer to a structure (structure contains pointer to a buffer) and 2 ints (x,y) which then computes the address of the byte containing (x,y) and returns the value in this address. (The buffer contains a bmp file) I have this function written in C and it works fine.
C function
int loadByte(imgInfo* pImg, int x, int y)
{
unsigned char *pPix = pImg->pImg + (((pImg->width + 31) >> 5) << 2) * y + (x >> 3);
return *pPix;
}
x86 function
load_byte:
push ebp ; prologue
mov ebp, esp
lea ecx, [ebp + 8]
mov ecx, [ecx] ; ecx = &imgInfo
mov eax, [ecx+0] ; eax = width
add eax, 31 ; eax = width + 31
sar eax, 5 ; eax = (width + 31) >> 5
sal eax, 2 ; eax = ((width + 31) >> 5) << 2
mul DWORD [ebp+16] ; eax * y
mov edx, [ebp+12] ; edx = x
sar edx, 3 ; edx = x>>3
add eax, edx ; eax = ((width + 31) >> 5) << 2 * y + (x >> 3)
mov edx, [ecx+8] ; edx = &pImg
add eax, edx
mov eax, [eax]
pop ebp ; epilogue
ret
I tried checking if the address computed in both functions is the same so I changed the return of C to return pPix and commented the line mov eax, [eax] in x86 and to my surprise both functions returned the same number but in the unchanged form (as in the code above) the x86 function always returns -1 for some reason. Is return *pPix not equivalent to mov eax, [eax]? What is wrong with my reasoning?
imgInfo struct
typedef struct
{
int width, height;
unsigned char* pImg; //buffer
int cX, cY;
int col;
} imgInfo;
load_byte C declaration
extern int load_byte(imgInfo* pInfo, int x, int y);

Mbed Cortex-m hardfault when sending data via TCP

I have a TCPSocket* object which holds a connection to a client. This object is passed to another object to send data back to the client:
uint32_t count = 10;
char* message = new char[4];
message[0] = count & 0xff;
message[1] = (count >> 8) & 0xff;
message[2] = (count >> 16) & 0xff;
message[3] = (count >> 24) & 0xff;
client->send(&message, 4);
When this part of the program is called, the following appears on the serial line, and no data is received by the client:
++ MbedOS Fault Handler ++
FaultType: HardFault
Context:
R0 : 00000000
R1 : 10008000
R2 : 00000004
R3 : 2007C000
R4 : 10000914
R5 : 00000000
R6 : 00000000
R7 : 10004330
R8 : 10004320
R9 : FFFFF435
R10 : 00000000
R11 : 00000000
R12 : 00012AC1
SP : 10002AF0
LR : 0000D1A1
PC : 00005938
xPSR : 21000000
PSP : 10002AD0
MSP : 10007FD8
CPUID: 412FC230
HFSR : 40000000
MMFSR: 00000000
BFSR : 00000082
UFSR : 00000000
DFSR : 0000000A
AFSR : 00000000
BFAR : 10008010
Mode : Thread
Priv : Privileged
Stack: PSP
-- MbedOS Fault Handler --
++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0xD337
Error Value: 0x5938
Current Thread: main Id: 0x10002B48 Entry: 0xD7D7 StackSize: 0x1000 StackMem: 0x10001B48 SP: 0x10007F88
For more info, visit: https://armmbed.github.io/mbedos-error/?error=0x80FF013D
-- MbedOS Error Info --
Everything is in one thread so I cant see what could be causing this.
These are the relevant parts of the program:
main:
// Network interface
EthernetInterface net;
TCPSocket listener; //listens for incoming connection requests
TCPSocket* client;
CommandProcessor commandProcessor(client);
int main() {
int remaining;
int rcount;
char *p;
char *buffer = new char[16];
nsapi_size_or_error_t result;
int n = net.set_network("192.168.1.103","255.255.255.0","192.168.1.2");
pc.printf("\n Success? %d\n", n);
net.connect();
listener.open(&net);
listener.bind(3045);
listener.listen(1);
client = listener.accept(NULL);
client->set_timeout(1000);
led1 = 1;
while(1) {
int remaining = 16;
int rcount = 0;
p = buffer;
while (remaining > 0 && 0 < (result = client->recv(p, remaining))) {
p += result;
rcount += result;
remaining -= result;
}
if (remaining == 0) //full message received
{
commandProcessor.process(buffer);
}
}
}
CommandProcessor:
CommandProcessor::CommandProcessor(TCPSocket* client)
{
this->client = client;
}
void CommandProcessor::process(char* message)
{
switch(message[0]) { //Command is first byte of message
case 0x3: {
uint32_t count = 10 ;
char* message = new char[4];
message[0] = count & 0xff;
message[1] = (count >> 8) & 0xff;
message[2] = (count >> 16) & 0xff;
message[3] = (count >> 24) & 0xff;
client->send(message, 4);
}
}
}
commandProcessor's client is NULL when you call commandProcessor.process(buffer).
Why don’t you create an instance of CommandProcessor after you get a pointer to a socket from accept().
CommandProcessor* commandProcessor;
client = listener.accept(NULL);
commandProcessor = new CommandProcessor(client);
commandProcessor->process(buffer);
Alternatively, you can set client with a function like this.
void CommandProcessor::setClient(TCPSocket* client) {
this->client = client;
}
usage:
client = listener.accept(NULL);
commandProcessor.setClient(client);

Why displays the Esp32 "nan" when using logarithem?

I´m building a weather staion with an Esp32 and a thermal resister. I want to display the value in Celsius. For the calculation i need the logarithem but when i use it, it always display "nan".
int ThermistorPin = 27;
int Vo;
float R1 = 10000;
float logR2, R2, T, Tc, Tf;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
void setup() {
Serial.begin(115200);
}
void loop() {
Vo = analogRead(A0);
R2 = R1 * (1023.0 / (float)Vo - 1.0);
logR2 = log(R2);
Serial.println(logR2);
T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2));
Tc = T - 273.15;
Serial.print("Temperature: ");
Serial.print(Tc);
Serial.println(" C");
delay(500);
}
I am not a mathematician, but the problem lies with the number 1023. That's the 10 bit resolution used by most Arduino's (Uno, Mega).
The ESP32 has a resolution of 12 bits, which gives the number 4095.
So, replace 1023 by 4095, because the ESP32 will generates numbers above 1023, up to 4095.
R2 = R1 * (4095/ (float)Vo - 1.0);
A small tip: c3*logR2*logR2*logR2 can be written as c3*pow(logR2 ,3)

for loop acts abnormally in Arduino

Consider the following loop in C:
int i;
for (i = 1; i > 0; i++);
After i reaches INT_MAX, it will turn INT_MIN at increment. Then i > 0 evaluates
false, and the for loop will terminate.
However, the same for loop will not terminate in Arduino, since i > 0 compares false
even if i is -32768.
Why is that?
PS. I'm using a Mega 2560 with Arduino version 1.0.5.
PPS. int is indeed 16 bit on Mega 2560
PPPS. The complete sketch below:
void setup () {
int i;
Serial.begin(9600);
for (i = 1; i > 0; i++);
}
void loop () {
Serial.println(100);
}
And I won't see any thing in the Serial Monitor
Disassembling the setup function gives:
0000014a <setup>:
14a: 80 e3 ldi r24, 0x30 ; 48
14c: 94 e0 ldi r25, 0x04 ; 4
14e: 40 e8 ldi r20, 0x80 ; 128
150: 55 e2 ldi r21, 0x25 ; 37
152: 60 e0 ldi r22, 0x00 ; 0
154: 70 e0 ldi r23, 0x00 ; 0
156: 42 d2 rcall .+1156 ; 0x5dc <_ZN14HardwareSerial5beginEm>
158: ff cf rjmp .-2 ; 0x158 <setup+0xe>
so now it's clear: avr-gcc thinks the i > 0 in for(i = 1; i > 0; i++) will never evaluates false and optimised the exit condition away.
Most likely, 'int' is also 32-bit on Arduino. It takes time to complete 2^31 iterations. You may change 'int' to 'short' and it should terminate as expected.
when int is defined, by default, its size is assumed to be of 16 bit by compiler.
But when you increment it beyond 32767 i.e.
int i=32767;
i++;
The size of 'i' is automatically increased to 32 bit. This is because the size is not specified in the declaration.
This causes your program not to stop at 32767.
Hence if you want to stop the for loop at 32767,
you have to specifically declare it as
short int i;
If you want to verify this, you can try following
short int x;
for(x=1; x>0; x++)
{
mySerial.println(x);
}
AND
int x;
for(x=1; x>0; x++)
{
mySerial.println(x);
}

Resources