Switching to privileged mode in cortex-m3 - cortex-m3

I'm trying to access the SysTick timer of Cortex-M3 so I've to switch to priviledged mode. I'm doing it as
/* Active previlige mode */
asm ("mov r0, #0x0");
asm ("msr control, r0");
asm ("ISB");
But it's not working because I'm unable to write the SYST_CSR register. Any exception entry is required to perform this operation if YES, how?

You cannot raise the mode to privileged directly from user mode (you can change to user mode direct from privileged mode). You have to do it via an SVC call (Supervisor call).
How you raise an SVC call will depend on your compiler if you do it in C, however in assembler you could use asm("svc, #1");
The #1 can be any number. This is made available to the SVC handler. If you want to only use the SVC handler for this purpose only then you don't need to decode the number in the handler and can simply use you assembly above to raise the privilege. However if you want to use the SVC for more than one purpose then you need to decode the number, so that #1 is for raising the privilege, #2 is for doing something else etc. The main thing to know here is that the SVC number will be on the stack you were using when the call was made (either the msp or psp). If you were only ever using one stack then it is easier. You will have to look up the stack frame in user guides.
So you need to Implement an SVC handler. You should be to find some examples on the web. There is a good example in the "Definitive Guide to ARM Cortex-M3 and Cortex M4" book.

Janathan Valvano has SysTick timer code example and other stuff at http://users.ece.utexas.edu/~valvano/arm/#Timer
; SysTickInts.s
; Runs on LM4F120/TM4C123
; Use the SysTick timer to request interrupts at a particular period.
; Daniel Valvano
; September 11, 2013
; This example accompanies the book
; "Embedded Systems: Introduction to ARM Cortex M Microcontrollers"
; ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2013
; Volume 1, Program 9.7
; "Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
; ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2013
; Volume 2, Program 5.12, section 5.7
;
;Copyright 2013 by Jonathan W. Valvano, valvano#mail.utexas.edu
; You may use, edit, run or distribute this file
; as long as the above copyright notice remains
;THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
;OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
;MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
;VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
;OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
;For more information about my classes, my research, and my books, see
;http://users.ece.utexas.edu/~valvano/
NVIC_ST_CTRL_R EQU 0xE000E010
NVIC_ST_RELOAD_R EQU 0xE000E014
NVIC_ST_CURRENT_R EQU 0xE000E018
NVIC_ST_CTRL_COUNT EQU 0x00010000 ; Count flag
NVIC_ST_CTRL_CLK_SRC EQU 0x00000004 ; Clock Source
NVIC_ST_CTRL_INTEN EQU 0x00000002 ; Interrupt enable
NVIC_ST_CTRL_ENABLE EQU 0x00000001 ; Counter mode
NVIC_ST_RELOAD_M EQU 0x00FFFFFF ; Counter load value
NVIC_SYS_PRI3_R EQU 0xE000ED20 ; Sys. Handlers 12 to 15 Priority
AREA |.text|, CODE, READONLY, ALIGN=2
THUMB
EXPORT SysTick_Init
; **************SysTick_Init*********************
; Initialize SysTick periodic interrupts, priority 2
; Input: R0 interrupt period
; Units of period are 1/clockfreq
; Maximum is 2^24-1
; Minimum is determined by length of ISR
; Output: none
; Modifies: R0, R1, R2, R3
SysTick_Init
; start critical section
MRS R3, PRIMASK ; save old status
CPSID I ; mask all (except faults)
; disable SysTick during setup
LDR R1, =NVIC_ST_CTRL_R ; R1 = &NVIC_ST_CTRL_R (pointer)
MOV R2, #0
STR R2, [R1] ; disable SysTick
; maximum reload value
LDR R1, =NVIC_ST_RELOAD_R ; R1 = &NVIC_ST_RELOAD_R (pointer)
SUB R0, R0, #1 ; counts down from RELOAD to 0
STR R0, [R1] ; establish interrupt period
; any write to current clears it
LDR R1, =NVIC_ST_CURRENT_R ; R1 = &NVIC_ST_CURRENT_R (pointer)
STR R2, [R1] ; writing to counter clears it
; set NVIC system interrupt 15 to priority 2
LDR R1, =NVIC_SYS_PRI3_R ; R1 = &NVIC_SYS_PRI3_R (pointer)
LDR R2, [R1] ; friendly access
AND R2, R2, #0x00FFFFFF ; R2 = R2&0x00FFFFFF (clear interrupt 15 priority)
ORR R2, R2, #0x40000000 ; R2 = R2|0x40000000 (interrupt 15 priority is in bits 31-29)
STR R2, [R1] ; set SysTick to priority 2
; enable SysTick with core clock
LDR R1, =NVIC_ST_CTRL_R ; R1 = &NVIC_ST_CTRL_R
; ENABLE SysTick (bit 0), INTEN enable interrupts (bit 1), and CLK_SRC (bit 2) is internal
MOV R2, #(NVIC_ST_CTRL_ENABLE+NVIC_ST_CTRL_INTEN+NVIC_ST_CTRL_CLK_SRC)
STR R2, [R1] ; store a 7 to NVIC_ST_CTRL_R
; end critical section
MSR PRIMASK, R3 ; restore old status
BX LR ; return
ALIGN ; make sure the end of this section is aligned
END ; end of file

Related

NASM local variables - are they, in fact, global macros?

I've been using the %local directive in NASM to define local variables and thus avoid typing [ebp - 8], [ebp - 24] etc. all the time.
However, I noticed that a local variable defined in one function between the preprocessor context %push and %pop is still available in the rest of the code, which may result in unexpected parsing errors.
Here, I've written a minimal example demonstrating the problem:
struc Rect
.left resd 1
.top resd 1
.width resd 1
.height resd 1
endstruc
%define RECT(x) g_rect + Rect. %+ x
segment .bss
g_rect resd 4
segment .text
; ================================================
function1:
%push
%stacksize flat
%assign %$localsize 0
%local width:dword ; defines local var "width"
push ebp
mov ebp, esp
sub esp, 4
pusha
; ...
popa
leave
ret
%pop
; ================================================
function2:
push ebp
mov ebp, esp
pusha
; ...
mov eax, RECT(height) ; OK
mov ebx, RECT(width) ; Parse error
; ...
popa
leave
ret
The exact error is:
nasm -f elf -d ELF_TYPE -g test.asm
test.asm:42: error: comma, colon, decorator or end of line expected after operand
Obviously, it happens because width is getting substituted with something else, and if I remove the local param definition, the problem goes away.
As you can see, the variable width is still available after the %pop. This doesn't look very local to me! I'd expect NASM to undefine width when the %pop is executed.
Is there a way to use %local but avoid these leaking macros? At the moment they act as a simple %define statement which is confusing.

*.s files cannot be correctly assembled in visualGDB

I am new to visualGDB. Recently I new a stm32 stand-alone project, any .cpp and .c files could be compiled correctly, but when i migrated µC/OS-II into the project, I found os_cpu_a.s file couldn't be assembled correctly.
Error logs are shown as follows:
And my Makefile flags setting is:
Please give me some suggestions! Any help will be appreciated!
os_cpu_a.s files content is shown below:
;/*********************** (C) COPYRIGHT 2010 Libraworks *************************
;* File Name : os_cpu_a.asm
;* Author : Librae
;* Version : V1.0
;* Date : 06/10/2010
;* Description : μCOS-II asm port for STM32
;*******************************************************************************/
IMPORT OSRunning ; External references
IMPORT OSPrioCur
IMPORT OSPrioHighRdy
IMPORT OSTCBCur
IMPORT OSTCBHighRdy
IMPORT OSIntNesting
IMPORT OSIntExit
IMPORT OSTaskSwHook
EXPORT OSStartHighRdy
EXPORT OSCtxSw
EXPORT OSIntCtxSw
EXPORT OS_CPU_SR_Save ; Functions declared in this file
EXPORT OS_CPU_SR_Restore
EXPORT PendSV_Handler
NVIC_INT_CTRL EQU 0xE000ED04
NVIC_SYSPRI2 EQU 0xE000ED20
NVIC_PENDSV_PRI EQU 0xFFFF0000
NVIC_PENDSVSET EQU 0x10000000
PRESERVE8
AREA |.text|, CODE, READONLY
THUMB
;********************************************************************************************************
; CRITICAL SECTION METHOD 3 FUNCTIONS
;
; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you
; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then
; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to
; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr'
; into the CPU's status register.
;
; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void);
; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);
;
;
; Note(s) : 1) These functions are used in general like this:
;
; void Task (void *p_arg)
; {
; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
; OS_CPU_SR cpu_sr;
; #endif
;
; :
; :
; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */
; :
; :
; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */
; :
; :
; }
;********************************************************************************************************
OS_CPU_SR_Save
MRS R0, PRIMASK
CPSID I
BX LR
OS_CPU_SR_Restore
MSR PRIMASK, R0
BX LR
OSStartHighRdy
LDR R4, =NVIC_SYSPRI2 ; set the PendSV exception priority
LDR R5, =NVIC_PENDSV_PRI
STR R5, [R4]
MOV R4, #0 ; set the PSP to 0 for initial context switch call
MSR PSP, R4
LDR R4, =OSRunning ; OSRunning = TRUE
MOV R5, #1
STRB R5, [R4]
LDR R4, =NVIC_INT_CTRL ;rigger the PendSV exception (causes context switch)
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
CPSIE I ;enable interrupts at processor level
OSStartHang
B OSStartHang ;should never get here
OSCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {R4, R5}
BX LR
OSIntCtxSw
PUSH {R4, R5}
LDR R4, =NVIC_INT_CTRL
LDR R5, =NVIC_PENDSVSET
STR R5, [R4]
POP {R4, R5}
BX LR
NOP
PendSV_Handler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP
CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
PendSV_Handler_Nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
end
By the way, it seems that any chinese character in edition will be treated as spam as a spam prevention method?So i have to delete all chinese comment in my code.

Performance Monitor Unit(PMU) data save

I am trying to calculate clock cycles of an assembly program consumed during execution through PMU in ARM1176JZF-S.
I am programming rapberry pi model b in assembly using baking-pi tutorials. The code for PMU that I am using is as below:
/* Enable PMU /
mov r0,#1
MCR p15, 0, r0, c15, c12, 0 ; Write Performance Monitor Control Register
/ Reset Cycle Counter /
mov r0,#5
MCR p15, 0, r0, c15, c12, 0 ; Write Performance Monitor Control Register
/ Meaure */
MRC p15, 0, r0, c15, c12, 1 # Read Cycle Counter Register
MRC p15, 0, r1, c15, c12, 1 # Read Cycle Counter Register
sub r0.r1.r0 # Cycle Count of
Is there any way I can save this data in a text or csv file on my SD card (value of r0)? so I can view my results after code execution.

Read a sector to address zero

%include "init.inc"
[org 0x0]
[bits 16]
jmp 0x07C0:start_boot
start_boot:
mov ax, cs
mov ds, ax
mov es, ax
load_setup:
mov ax, SETUP_SEG
mov es, ax
xor bx, bx
mov ah, 2 ; copy data to es:bx from disk.
mov al, 1 ; read a sector.
mov ch, 0 ; cylinder 0
mov cl, 2 ; read data since sector 2.
mov dh, 0 ; Head = 0
mov dl, 0 ; Drive = 0
int 0x13 ; BIOS call.
jc load_setup
lea si, [msg_load_setup]
call print
jmp $
print:
print_beg:
mov ax, 0xB800
mov es, ax
xor di, di
print_msg:
mov al, byte [si]
mov byte [es:di], al
or al, al
jz print_end
inc di
mov byte [es:di], BG_TEXT_COLOR
inc di
inc si
jmp print_msg
print_end:
ret
msg_load_setup db "Loading setup.bin was completed." , 0
times 510-($-$$) db 0
dw 0xAA55
I want to load setup.bin to memory address zero. So, I input 0 value to es register (SETUP_SEG = 0). bx, too. But it didn't work. then, I have a question about this issue. My test is below.
SETUP_SEG's value
0x0000 : fail
0x0010 : success
0x0020 : fail
0x0030 : fail
0x0040 : fail
0x0050 : success
I can't understand why this situation was happened. All test was carried out on VMware. Does anyone have an idea ?
I'm not sure if this is your problem, but your trying to load setup.bin in the Real Mode IVT (Interrupt Vector Table). The IVT contains the location of each interrupt, so I'm assuming that your boatloader is overwriting them when it loads setup.bin into memory! Interrupts can be sneaky and tricky, since they can be called even if you didn't call them. Any interrupt vector you overwrote will likely cause undefined behavior when called, which will cause some problems.
I suggest setting SETUP_SEG to a higher number like 0x2000 or 0x3000, but the lowest you could safely go is 0x07E0. The Osdev Wiki and Wikipedia have some helpful information on conventional memory and memory mapping.
I hope this helps!

Analog read from all 7 inputs using PRU and a host C program for beaglebone black

I'm kinda new to the beaglebone black world running on a AM335X Cortex A8 processor and I would like to use the PRU for fast analog read with the maximum sampling rate possible.
I would like to read all 7 inputs in a loop form like:
while( n*7 < sampling_rate){ //initial value for n = 0
read(AIN0); //and store it in shared memory(7*n + 0)
read(AIN1); //and store it in shared memory(7*n + 1)
read(AIN2); //and store it in shared memory(7*n + 2)
read(AIN3); //and store it in shared memory(7*n + 3)
read(AIN4); //and store it in shared memory(7*n + 4)
read(AIN5); //and store it in shared memory(7*n + 5)
read(AIN6); //and store it in shared memory(7*n + 6)
n++;
}
so that I can read them from a host program running on the main processor. Any idea how to do so? I tried using a ready code called ADCCollector.c from a package named AM335x_pru_package but I can't figure out how to get all the addresses and values of the registers used.
This is the code I was trying to modify (ADCCollector.p):
.origin 0 // offset of the start of the code in PRU memory
.entrypoint START // program entry point, used by debugger only
#include "ADCCollector.hp"
#define BUFF_SIZE 0x00000fa0 //Total buff size: 4kbyte(Each buffer has 2kbyte: 500 piece of data
#define HALF_SIZE BUFF_SIZE / 2
#define SAMPLING_RATE 1 //Sampling rate(16khz) //***//16000
#define DELAY_MICRO_SECONDS (1000000 / SAMPLING_RATE) //Delay by sampling rate
#define CLOCK 200000000 // PRU is always clocked at 200MHz
#define CLOCKS_PER_LOOP 2 // loop contains two instructions, one clock each
#define DELAYCOUNT DELAY_MICRO_SECONDS * CLOCK / CLOCKS_PER_LOOP / 1000 / 1000 * 3 //if sampling rate = 98000 --> = 3061.224
.macro DELAY
MOV r10, DELAYCOUNT
DELAY:
SUB r10, r10, 1
QBNE DELAY, r10, 0
.endm
.macro READADC
//Initialize buffer status (0: empty, 1: first buffer is ready, 2: second buffer is ready)
MOV r2, 0
SBCO r2, CONST_PRUSHAREDRAM, 0, 4
INITV:
MOV r5, 0 //Shared RAM address of ADC Saving position
MOV r6, BUFF_SIZE //Counting variable
READ:
//Read ADC from FIFO0DATA
MOV r2, 0x44E0D100
LBBO r3, r2, 0, 4
//Add address counting
ADD r5, r5, 4
//Write ADC to PRU Shared RAM
SBCO r3, CONST_PRUSHAREDRAM, r5, 4
DELAY
SUB r6, r6, 4
MOV r2, HALF_SIZE
QBEQ CHBUFFSTATUS1, r6, r2 //If first buffer is ready
QBEQ CHBUFFSTATUS2, r6, 0 //If second buffer is ready
QBA READ
//Change buffer status to 1
CHBUFFSTATUS1:
MOV r2, 1
SBCO r2, CONST_PRUSHAREDRAM, 0, 4
QBA READ
//Change buffer status to 2
CHBUFFSTATUS2:
MOV r2, 2
SBCO r2, CONST_PRUSHAREDRAM, 0, 4
QBA INITV
//Send event to host program
MOV r31.b0, PRU0_ARM_INTERRUPT+16
HALT
.endm
// Starting point
START:
// Enable OCP master port
LBCO r0, CONST_PRUCFG, 4, 4 //#define CONST_PRUCFG C4 taken from ADCCollector.hp
CLR r0, r0, 4
SBCO r0, CONST_PRUCFG, 4, 4
//C28 will point to 0x00012000 (PRU shared RAM)
MOV r0, 0x00000120
MOV r1, CTPPR_0
ST32 r0, r1
//Init ADC CTRL register
MOV r2, 0x44E0D040
MOV r3, 0x00000005
SBBO r3, r2, 0, 4
//Enable ADC STEPCONFIG 1
MOV r2, 0x44E0D054
MOV r3, 0x00000002
SBBO r3, r2, 0, 4
//Init ADC STEPCONFIG 1
MOV r2, 0x44E0D064
MOV r3, 0x00000001 //continuous mode
SBBO r3, r2, 0, 4
//Read ADC and FIFOCOUNT
READADC
Another question is: if I simply changed the #define Sampling_rate from 16000 to any other number below or equal to 200000 in the (.p) file, I will get that sampling rate? or should I change other things?
Thanks in advance.
I used the c wrappers from libpruio: http://www.freebasic.net/forum/viewtopic.php?f=14&t=22501
and then use this code to get all my ADC values:
#include "stdio.h"
#include "c_wrapper/pruio.h" // include header
#include "sys/time.h"
//! The main function.
int main(int argc, char **argv) {
struct timeval start, now;
long mtime, seconds, useconds;
gettimeofday(&start, NULL);
int i,x;
pruIo *io = pruio_new(PRUIO_DEF_ACTIVE, 0x98, 0, 1); //! create new driver structure
if (pruio_config(io, 1, 0x1FE, 0, 4)){ // upload (default) settings, start IO mode
printf("config failed (%s)\n", io->Errr);}
else {
do {
gettimeofday(&now, NULL);
seconds = now.tv_sec - start.tv_sec;
useconds = now.tv_usec - start.tv_usec;
mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;
printf("%lu",mtime);
for(i = 1; i < 9; i++) {
printf(",%d", io->Adc->Value[i]); //0-66504 for 0-1.8v
}
printf("\n");
x++;
}while (mtime < 100);
printf("count: %d \n", x);
pruio_destroy(io); /* destroy driver structure */
}
return 0;
}
In your example you use libpruio in IO mode (synchronous) and therefore you have no control over the sampling rate, since the host CPU doesn't work in real-time.
To get the maximum sampling rate (as mentioned in the OP) you have to use either RB or MM mode. In those modes libpruio buffers the samples in memory and the host can access them asynchronously. See example rb_file.c (or triggers.bas) in the libpruio package.