-
Notifications
You must be signed in to change notification settings - Fork 11
Language Reference
- simpPRU is a procedural programming language.
- It is a statically typed language. Variables and functions must be assigned data types during compilation.
- It is typesafe, and data types of variables are decided during compilation.
- simPRU codes have a
.sim
extension.
-
int
- Integer datatype -
bool
- Boolean datatype -
void
- Void datatype, can only be used a return type for functions
-
<any_integer>
- Integer constant -
true
- Boolean constant (True) -
false
- Boolean constant (False) -
Px_yz
- Pin mapping constants are Integer constant, where x is 1,2 or 8,9 and yz are the header pin numbers. For further details refer to this
-
{
,}
- Braces -
(
,)
- Parenthesis -
/
,*
,+
,-
- Arithmetic operators -
>
,<
,==
,!=
,>=
,<=
- Comparison operators -
~
,&
,|
- Bitwise operators: not, and, or -
not
,and
,or
- Logical operators: not, and, or -
:=
- Assignment operator
Bitwise operators and Logical operators cannot be interchangeably used.
Correct: bool test := true & false | (false and true);
Wrong: bool test := true & false | false and true;
- Result of Arithmetic operator is Integer constant.
- Result of Comparison, Bitwise and Logical operators is Boolean constant.
- Only Integer constants can be used with Arithmetic operators.
- Only Integer constants can be used with Comparison operators.
- Only Boolean constants can be used with Bitwise and Logical operators.
Correct: bool out := 5 > 6;
Wrong: int yy := 5 > 6;
- Datatype of variable needs to be specified during compile time.
- Variables can be assigned values after declarations.
- If variable is not assigned a value after declaration, it is set to
0
forinteger
and tofalse
forboolean
by default. - Variables can be assigned other variables of same datatype.
- Variables can be assigned expressions whose output is of same datatype.
int var;
bool test_var;
int var := 99;
bool test_var := false;
var := 45;
test_var := true;
- Variables to be assigned must be declared earlier.
- Datatype of the variables cannot change. Only appropriate expressions/constants of their respective datatypes can be assigned to the variables.
- Integer variable can be assigned only Integer expression/constant.
- Boolean variable can be assigned only Boolean expression/constant.
- TBD
true |
read_counter |
stop_counter |
false |
start_counter |
pwm |
int |
delay |
digital_write |
bool |
digital_read |
def |
void |
return |
or |
if |
and |
not |
elif |
continue |
break |
else |
while |
in |
for |
init_message_channel |
send_message |
receive_message |
-
An identifier/variable name must be start with an alphabet or underscore (_) only, no other special characters, digits are allowed as first character of the identifier/variable name.
product_name, age, _gender
-
Any space cannot be used between two words of an identifier/variable; you can use underscore (_) instead of space.
product_name, my_age, gross_salary
-
An identifier/variable may contain only characters, digits and underscores only. No other special characters are allowed, and we cannot use digit as first character of an identifier/variable name (as written in the first point).
length1, length2, _City_1
Detailed info: https://www.includehelp.com/c/identifier-variable-naming-conventions.aspx
=> ((3+3)/2)
=> 3
=> (false & true) | ~false
=> true
=> (true and true) & (not false)
=> true
=> (3 > 4) and false
=> false
=> (4 != 3) & (false and true)
=> false
=> true
=> true
=> false
=> false
!!! Note Expressions are evaluated following the operator precedence
Statements in the if-block are executed only if the if-expression evaluates to true
. If the value of expression is true
, statement1 and any other statements in the block are executed and the else-block, if present, is skipped. If the value of expression is false
, then the if-block is skipped and the else-block, if present, is executed. If elif-block are present, they are evaluated, if they become true
, the statement is executed, otherwise, it goes on to eval next set of statements
if : boolean_expression {
statement 1
...
...
}
elif : boolean_expression {
statement 2
...
...
...
}
else {
statement 3
...
...
}
int a := 3;
if : a != 4 {
a := 4;
}
elif : a > 4 {
a := 10;
}
else {
a := 0;
}
- This will evaluate as follows, since
a = 3
, if-block (3!=4
) will evaluate to true, and value of a will be set to 4, and program execution will stop.
For loop is a range based for loop. Range variable is a local variable with scope only inside the for loop.
for : var in range_1:range_2 {
statement 1
....
....
}
- Here, for loop is a range based loop, value of integer variable
var
will vary fromrange_1
torange_2 - 1
. Value ofvar
doesnot equalrange_2
. As of now range can't be reversed,i.e.,range_1 < range_2
📔 var is a integer, and range_1, range_2 can be arithmetic expression, integer variable or integer constant.
int sum := 0;
for : i in 1:4 {
sum = sum + i;
}
int mx := 32;
int nt;
for : j in 2:mx-10 {
nt := nt + j;
}
While loop statement repeatedly executes a target statement as long as a given condition is true.
while : boolean_expression {
statement 1
...
...
}
- Infinite loop
while true {
do_something..
...
}
- Normal loop, will repeat 30 times, before exiting
int tag := 0;
while : tag < 30 {
tag := tag + 1;
}
⚠️ break
andcontinue
should only be used inside looping statements
break
is used to break execution in a loop statement, either for loop
or while loop
. It exits the loop upon calling.
break;
for : i in 0:9 {
if : i == 3 {
break;
}
}
continue
is used to continue execution in a loop statement, either for loop
or while loop
.
continue;
for : j in 9:19 {
if : i == 12 {
continue;
}
else {
break;
}
}
A function is a group of statements that together perform a task. You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is such that each function performs a specific task. A function declaration tells the compiler about a function's name, return type, and parameters. A function definition provides the actual body of the function.
⚠️ Function must be defined before calling it.
def <function_name> : <data_type> : <data_type> <param_name>, <data_type> <param_name>, ... {
statement 1;
...
...
return <data_type>;
}
📔 If return data type is void, then return statement is not needed, and if still it is added, it must be return nothing, i.e., something like this
return ;
⚠️ return
can only be present in the body of the function only once, that too at the end of the function, not inside any compound statements.
❌
return
inside a compound statement, this syntax is not allowed.
def test : int : int a {
if : a < 4 {
return a;
}
}
✅
return
is not inside compound statments, It should be placed only at the end of function definition
def test : int : int a {
int gf := 8;
if : a < 4 {
gf := 4;
}
return gf;
}
Examples according to return types
- integer
def test_func : int : int a, int b {
int aa := a + 5;
if : aa < 3 {
aa : = 0;
}
return aa + b;
}
- boolean
def compare : bool : int val {
bool ret := false;
if : val < 0 {
ret := true;
}
return ret;
}
- void
def example_func : void : bool qu {
if : qu and true {
...
do something
...
}
}
def example_func_v : void : {
int temp := 90;
return;
}
Functions can be called only if, they have been defined earlier. They return data types according to their definition. Parameters are passed by value. Only pass by value is supported as of now.
function_name(var1, var2, ..);
We will consider functions defined in earlier subsection
- integer
int a := 55;
int ret_val := test_func(4, a);
- boolean
bool val := compare(22);
compare(-2);
- void
example_func(false);
example_func_v();
-
PocketBeagle
-
PRU0
R30 Register bit (Output) R31 Register bit (Input) Header pin - 16 P1_20 7 7 P1_29 4 4 P1_31 1 1 P1_33 0 0 P1_36 - 15 P2_18 15 - P2_33 - 14 P2_22 14 - P2_24 6 6 P2_28 3 3 P2_30 2 2 P2_32 5 5 P2_34 -
PRU1
R30 Register bit (Output) R31 Register bit (Input) Header pin 9 9 P1_02 11 11 P1_04 15 15 P1_30 14 14 P1_32 10 10 P1_35 - 16 P2_31 8 8 P2_35
-
-
BeagleBone Black
-
PRU0
R30 Register bit (Output) R31 Register bit (Input) Header pin - 15 P8_15 15 - P8_11 - 14 P8_16 14 - P8_12 7 7 P9_25 5 5 P9_27 3 3 P9_28 1 1 P9_29 2 2 P9_30 0 0 P9_31 6 6 P9_41 4 4 P9_42 -
PRU1
R30 Register bit (Output) R31 Register bit (Input) Header pin 13 13 P8_20 12 12 P8_21 8 8 P8_27 10 10 P8_28 9 9 P8_29 6 6 P8_39 7 7 P8_40 4 4 P8_41 5 5 P8_42 2 2 P8_43 3 3 P8_44 0 0 P8_45 1 1 P8_46 ** Before using these pins, you need to disable HDMI functionality.
You can read how to do this here
-
-
BeagleBone Black Wireless
-
PRU0
R30 Register bit (Output) R31 Register bit (Input) Header pin - 15 P8_15 15 - P8_11 - 14 P8_16 14 - P8_12 7 7 P9_25 5 5 P9_27 3 3 P9_28 1 1 P9_29 2 2 P9_30 0 0 P9_31 6 6 P9_41 4 4 P9_42 -
PRU1
R30 Register bit (Output) R31 Register bit (Input) Header pin 13 13 P8_20 12 12 P8_21 8 8 **P8_27 10 10 **P8_28 9 9 **P8_29 6 6 **P8_39 7 7 **P8_40 4 4 **P8_41 5 5 **P8_42 2 2 **P8_43 3 3 **P8_44 0 0 **P8_45 1 1 **P8_46 ** Before using these pins, you need to disable HDMI functionality.
You can read how to do this here
-
-
BeagleBone AI
-
PRU0
R30 Register bit (Output) R31 Register bit (Input) Header pin 3 3 P8_12 4 4 P8_11 5 5 P9_15 17 17 P9_26 -
PRU1
R30 Register bit (Output) R31 Register bit (Input) Header pin 1 1 P9_20 2 2 P9_19 3 3 P9_41 5 5 P8_18 6 6 P8_19 7 7 P8_13 9 9 P8_14 10 10 P9_42 11 11 P9_27 14 14 P9_14 15 15 P9_16 16 16 P8_15 17 17 P8_26 18 18 P8_16 -
PRU2
R30 Register bit (Output) R31 Register bit (Input) Header pin 10 10 P8_33 11 11 P8_31 6 6 P8_38 7 7 P8_36 20 20 P8_08 15 15 P9_13 3 3 P8_39 2 2 P8_42 9 9 P8_35 8 8 P8_34 5 5 P8_37 4 4 P8_40 17 17 P8_28 18 18 P8_29 19 19 P8_30 1 1 P8_41 0 0 P8_44 14 14 P9_11 -
PRU3
R30 Register bit (Output) R31 Register bit (Input) Header pin 0 0 P8_32 5 5 P9_25 6 6 P8_09 10 10 P9_31 8 8 P9_18 16 16 P8_07 15 15 P8_10 17 17 P8_27 20 20 P8_43 18 18 P8_45 19 19 P8_46 9 9 P9_17 13 13 P9_28 11 11 P9_29 12 12 P9_30 ** Before using these pins, you need to disable HDMI functionality.
You can read how to do this here
-
-
All Header pins are
constant integer variable
by default, with its value equal to respective R30/R31 register bit- Example:
P1_20
is an constant integer variable with value16
, similaryP1_02
is an constant integer variable with value9
- Example:
digital_write
is a function which enables PRU to write given logic level at specified output pin. It is a function with void return type and it's parameters are integer
and boolean
, first parameter is the pin number to write to or PRU R30 register bit and second parameter is boolean
value to be written. true
for HIGH and false
for LOW.
digital_write(pin_number, value);
-
pin_number
is an integer. It must be a header pin name which supports output, or PRU R30 Register bit. -
value
is a boolean. It is used to set logic level of the output pin,true
for HIGH andfalse
for LOW.
-
void
- returns nothing.
int a := 32;
if : a < 32 {
digital_write(P1_29, true);
}
else {
digital_write(P1_29, false);
}
If the value of a < 32, then pin P1_29
is set to HIGH
or else it is set to LOW
.
digital_read
is a function which enables PRU to read logic level at specified input pin. It is a function with return type boolean
and it's parameter is a integer
whose value must be the pin number to be read or PRU R31 register bit.
digital_read(pin_number);
-
pin_number
is an integer. It must be a header pin name which supports input, or PRU R31 Register bit.
-
boolean
- returns the logic level of the pin number passed to it. It returnstrue
for HIGH andfalse
for LOW.
if digital_read(P1_20) {
digital_write(P1_29, false);
}
else {
digital_write(P1_29, true);
}
Logic level of pin P1_20
is read. If it is HIGH, then pin P1_29
is set to LOW
, or else it is set to HIGH
.
delay
is a function which makes PRU wait for specified milliseconds. When this is called PRU does absolutely nothing, it just sits there waiting.
delay(time_in_ms);
-
time_in_ms
is an integer. It is the amount of time PRU should wait in milliseconds. (1000 milliseconds = 1 second).
-
void
- returns nothing.
digital_write(P1_29, true);
delay(2000);
digital_write(P1_29, false);
Logic level of pin P1_29
is set to HIGH
, PRU waits for 2000 ms = 2 seconds, and then sets the logic level of pin P1_29
to LOW
.
start_counter
is a function which starts PRU's internal counter. It counts number of CPU cycles. So it can be used to count time elapsed, as it is known that each cycle takes 5 nanoseconds.
start_counter()
- n/a
-
void
- returns nothing.
start_counter();
stop_counter
is a function which stops PRU's internal counter.
stop_counter()
- n/a
-
void
- returns nothing.
stop_counter();
read_counter
is a function which reads PRU's internal counter and returns the value. It counts number of CPU cycles. So it can be used to count time elapsed, as it is known that each cycle takes 5 nanoseconds.
read_counter()
- n/a
-
integer
- returns the number of cycles elapsed since callingstart_counter
.
start_counter();
while : read_counter < 200000000 {
digital_write(P1_29, true);
}
digital_write(P1_29, false);
stop_counter();
while the value of hardware counter is less than 200000000, it will set logic level of pin P1_29
to HIGH
, after that it will set it to LOW
. Here, 200000000 cpu cycles means 1 second of time, as CPU clock is 200 MHz. So, LED will turn on for 1 second, and turn off after.
init_message_channel
is a function which is used to initialise communication channel between PRU and the ARM core. It is sets up necessary structures to use RPMSG to communicate, it expects a init message from the ARM core to initialise. It is a necessary to call this function before using any of the message functions.
init_message_channel()
- n/a
-
void
- returns nothing
init_message_channel();
receive_message
is a function which is used to receive messages from ARM to the PRU, messages can only be integers
, as only they are supported as of now. It uses RPMSG channel setup by init_message_channel
to receive messages from ARM core.
receive_message()
- n/a
-
integer
- returns integer data received from PRU
init_message_channel();
int emp := receive_message();
if : emp >= 0 {
digital_write(P1_29, true);
}
else {
digital_write(P1_29, false);
}
send_message
is a function which is used to send messages to ARM core from PRU, messages can only be integers
. It uses RPMSG channel setup by init_message_channel
to send messages from PRU to the ARM core.
send_message(message)
-
message
is an integer, number passed to it is sent to the ARM core, through RPMSG.
init_message_channel();
if : digital_read(P1_29) {
send_message(1);
}
else {
send_message(0);
}
-
For detailed docs, visit: https://simppru.readthedocs.io/en/latest/
-
For progress log, visit: https://ve0x10.in/gsoc2020/