Read/Write in Array of Structure stock in a persistant variable - codesys

I'm working on codesys (ST) to create a storekeeper programm.
I have a persistant variable which is a strucure name ST_STORAGE, here it definition :
TYPE ST_STORAGE :
STRUCT
xInitialized :BOOL; // Indicate if the storage have been already initialized
astStore :ARRAY[0..9 ,0..9] OF ST_Location; // Indicate location (composed of columns and rows) available in all storage
uiNbColumns :UINT; // Indicate number of columns that are really availablein this storage
uiNbRows :UINT; // Indicate number of rows that are really available in this storage
END_STRUCT
END_TYPE
The structure ST_LOCATION is composed of :
TYPE ST_LOCATION :
STRUCT
xEmpty :BOOL; // Indicate if location is used or empty
uiColumn :UINT; // Indicate location's column where tool is stored
uiRow :UINT; // Indicate location's row where tool is stored
stToolRef :STRING; // Indicate RFID reference of tool stored
END_STRUCT
END_TYPE
My function block FB_Storage take in input :
VAR_INPUT
i_xInitialize :BOOL; // Indicate initializing instruction (init MAX column and row of the store)
i_xScan :BOOL; // Indicate scanning instruction (scanning locations to find our tool's reference)
i_xStore :BOOL; // Indicate storing instruction (storing a tool reference in a specified location)
i_xPickUp :BOOL; // Indicate picking up instruction (pick up a tool in specified location and clean location after picking up)
i_sToolRef :STRING; // Indicate Tool ref to store in a speciefied location
i_stStorage :POINTER TO ST_STORAGE; // Indicate the storage to scan,store,pick up in
END_VAR
So i can write / read in my storage by the pointer i_stStorage. But i can't read or write in my speciefied location by :
i_stStorage^.astStore[x,y].xEmpty

Related

How do I properly model internal memory in my serial flash device?

I am writing a model for a serial flash device. I wonder how do I best model the internal memory? I would like the memory size to be configurable by the user since I intend to reuse this model for different serial flashes. It also needs to retain its content upon reset while the rest of the logic is reset.
I tried using a statically allocated character buffer but that is not configurable and seems very inappropriate for such large sizes as my flash model. My flash model is 512 MB.
saved char flash_image[512 * 1024 * 1024];
Assuming this will go into Simics, it is best modeled with two subobjects, both of which are available in Simics Base.
The first is an image which stores the actual data, the second is a ram which is used to read/write into the image.
Both the image and the ram are connects using the init_as_subobj template which makes Simics automatically create them as sub-objects of the device.
They are placed in a group where we can add an init method, which sets default values for the required attributes of the subobjects; in this case the "size" of the image and the "image" of the ram.
The ram object also uses the map_target template, which gives us useful methods for reading and writing into the ram.
dml 1.4;
device sample_dev;
import "utility.dml";
import "simics/simulator-api.dml";
group flash is init {
param size = 0x1000;
method init() {
SIM_set_attribute_default(
ram.obj, "image", SIM_make_attr_object(image.obj));
SIM_set_attribute_default(
image.obj, "size", SIM_make_attr_uint64(size));
}
connect image is init_as_subobj {
param classname = "image";
}
connect ram is (init_as_subobj, map_target) {
param classname = "ram";
}
}
method write_test() {
try
flash.ram.write(0, 1, 42);
catch
log error: "write failed, it shouldn't!";
}
The size of the image is given a default value by a parameter in this example, but it can also be set or overridden by the user when creating the object, by assigning to the attribute flash.image.size, e.g. like this:
SIM_create_object("sample_dev", "dev", **{"flash.image.size": 0x2000})

ACT-r: assigning a chunk as buffer slot value in a production rule

No sure if there's a lot of act-r programmer on here, but I can't seem to find a forum/group for that anywhere so...
I'm writing a program which as a chunk defined as (and the goal below):
(chunk-type position position-x position-y)
(chunk-type goal state last-pos)
In a production, I'm fetching the position of a thing on screen from the visual-location and then I would need to create a position chunk and put that in my goal's last-pos slot. Here's the production rule:
(P attend-projectile
=goal>
ISA goal
state nil
=visual-location>
screen-x =pos-x
screen-y =pos-y
?visual>
state free
==>
+visual>
cmd move-attention
screen-pos =visual-location
=goal>
state attended
last-pos (position pos-x screen-x pos-y screen-y)
)
Or something like that. I've tried various syntaxe. The problem boils down to:
I need to instantiate a chunk within a production (the position chunk) based on values recovered in the lhs,
then assign that chunk to a goal's slot.
Somehow I can't seem to find an equivalent example in the doc...
EDIT:
I do need this to be a chunk, not just storing the x & y position. Eventually this chunk will be extended to include an ID (which will be obtained from the visual location, e.g. a different letter will be assigned to each moving object). I will be tracking those object through time. Because I'm tracking through time, another chunk (trajectory) will contain 3 position chunks (with their IDs).
Other productions will expect to find this chunk (trajectory, once I have 3 position chunks) and make decisions based on that.
Obviously the above is a snippet of the code. But the conceptual difficulty I have is manipulating (instantiating/creating however it's called in actr nomentalture) chunks at runtime, essentially.
Why do you need another chunk? You have the chunk in the visual-location buffer with that information so why not use it:
(P attend-projectile
=goal>
ISA goal
state nil
=visual-location>
?visual>
state free
==>
+visual>
cmd move-attention
screen-pos =visual-location
=goal>
state attended
last-pos =visual-location
)
Of course, that doesn't answer the question that was asked.
To create a new chunk, the proper way to do so is through a request to the imaginal buffer which would then require a following production to harvest the result and place it into the slot of the goal buffer's chunk. Assuming that the slots you want in the new chunk are from the position chunk-type you show, and that the values are from the similarly named slots of the chunk in the visual-location buffer, this would create the new chunk in the imaginal buffer:
(P attend-projectile
=goal>
ISA goal
state nil
=visual-location>
screen-x =pos-x
screen-y =pos-y
?visual>
state free
==>
+visual>
cmd move-attention
screen-pos =visual-location
=goal>
state attended
+imaginal>
position-x =pos-x
position-y =pos-y
)

B&R get drive serial number via MC_BR_GetHardwareInfo function block

I'm trying to retrieve the serial number from a drive using the MC_BR_GetHardwareInfo function block. Since the documentation lacks any kind of example code on this topic I'm getting nowhere.
Which information should I provide to the function block in order to get the desired serial number?
Below sample will crash in the PLC, probably because the function block requires certain pointers to be addressed:
MC_HARDWARE_INFO_REF hwinfo;
MC_BR_GetHardwareInfo(&hwinfo);
You are probably getting a page fault, because you provide the MC_BR_GetHardwareInfo function block (FUB) a wrong type, which leads to random behavior.
A function block is basically a function which requires a reference to a specific type as parameter. This type contains the actual in- and outputs which are used, internal state variables, etc. We need this, because of the synchronous execution of the code. This means unlike a function, you need to call a FUB until it is done.
Let's take a look to the help of the FUB:
Guid: 056444ea-2a15-4af6-a5ae-0675894b17d3
So the FUB needs a reference to the Axis object of which you want to know the HW info and an Execute command. It will give you some status bits, an error code and the actual data you want to have within the structure HardwareInfo of the type MC_HARDWARE_INFO_REF.
First we need to instantiate the FUB by create a variable of its type. We do this in the local *.var file of the task:
VAR
fbGetHwInfo : MC_BR_GetHardwareInfo := (0);
END_VAR
Then we call set the parameters of the FUB and call it, which might look like this:
void _CYCLIC ProgramCyclic(void)
{
//should be set by the application or in watch/monitor; now it only
//executes once
fbGetHwInfo.Execute = 1;
//reference to your axis object; when using a wizard the first axis
//will be gAxis01 on default
fbGetHwInfo.Axis = (UDINT)&gAxis01;
//call the FUB
MC_BR_GetHardwareInfo(&fbGetHwInfo);
if(fbGetHwInfo.Error == 1)
{
//TODO: errorhandling
}
else if(fbGetHwInfo.Done == 1)
{
//TODO use output
//fbGetHwInfo.HardwareInfo
}
}
typically you would do this in some statemachine. Also you probably have to wait until the network to the drive is initialized. You could check this with the MC_BR_ReadDriveStatus FUB. Just for testing it should be enough to wait for some seconds after reboot and set the Execute flag in monitor mode.

In Application Programming issue

I'm working on project on STM32L152RCT6, where i have to build a mechanism to self update the code from the newly gated file(HEX file).
For that i have implemented such mechanism like boot loader where it checks for the new firmware if there it it has to cross verify and if found valid it has to store on "Application location".
I'm taking following steps.
Boot loader address = 0x08000000
Application address = 0x08008000
Somewhere on specified location it has to check for new file through Boot loader program.
If found valid it has to be copy all the HEX on location(as per the guide).
Than running the application code through jump on that location.
Now problem comes from step 5, all the above steps I've done even storing of data has been done properly(verify in STM32 utility), but when i'm jump to the application code it won't work.
Is there i have to cross check or something i'm missing?
Unlike other ARM controllers that directly jump to address 0 at reset, the Cortex-M series takes the start address from a vector table. If the program is loaded directly (without a bootloader), the vector table is at the start of the binary (loaded or mapped to address 0). First entry at offset 0 is the initial value of the stack pointer, second entry at address 4 is called the reset vector, it contains the address of the first instruction to be executed.
Programs loaded with a bootloader usually preserve this arrangement, and put the vector table at the start of the binary, 0x08008000 in your case. Then the reset vector would be at 0x08008004. But it's your application, you should check where did you put your vector table. Hint: look at the .map file generated by the linker to be sure. If it's indeed at 0x08008000, then you can transfer control to the application reset vector so:
void (*app)(void); // declare a pointer to a function
app = *(void (**)(void))0x08008004; // see below
app(); // invoke the function through the pointer
The complicated cast in the second line converts the physical address to a pointer to a pointer to a function, takes the value pointed to it, which is now a pointer to a function, and assigns it to app.
Then you should manage the switchover to the application vector table. You can do it either in the bootloader or in the application, or divide the steps between them.
Disable all interrupts and stop SysTick. Note that SysTick is not an interrupt, don't call NVIC_DisableIRQ() on it. I'd do this step in the bootloader, so it gets responsible to disable whatever it has enabled.
Assign the new vector table address to SCB->VTOR. Beware that the boilerplate SystemInit() function in system_stm32l1xx.c unconditionally changes SCB->VTOR back to the start of the flash, i.e. to 0x08000000, you should edit it to use the proper offset.
You can load the stack pointer value from the vector table too, but it's tricky to do it properly, and not really necessary, the application can just continue to use the stack that was set up in the bootloader. Just check it to make sure it's reasonable.
Have you changed the application according to the new falsh position?
For example the Vector Table has to be set correctl via
SCB->VTOR = ...
When your bootloader starts the app it has to configure everything back to the reset state as the application may relay on the default reset values. Espessially you need to:
Return values of all hardware registers to its reset values
Switch off all peripheral clocks (do not forget about the SysTick)
Disable all enabled interrupts
Return all clock domains to its reset values.
Set the vector table address
Load the stack pointer from the beginning of the APP vector table.
Call the APP entry point.(vertor table start + 4)
Your app has to be compiled and linked using the custom linker script where the FLASH start point is 0x8008000
for example:
FLASH (rx) : ORIGIN = 0x8000000 + 32K, LENGTH = 512K - 32K
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
where FLASH_BASE's value must be equal to the address of your IROM's value in KEIL
example:
#define FLASH_BASE 0x08004000
Keil configuration

Using burst_read/write with register model

I've a register space of 16 registers.
These are accessible through serial bus (single as well as burst).
I've UVM reg model defined for these registers.
However none of the reg model method supports burst transaction on bus.
As a workaround
I can declare memory model for same space and whenever I need burst access I use memory model but it seems redundant to declare 2 separate classes for same thing and this approach won't mirror register values correctly.
create a function which loops for number of bytes iterations and access registers one by one however this method doesn't create burst transaction on bus.
So I would like to know if there is a way to use burst_read and burst_write methods with register model. It would be nice if burst_read and burst_write support mirroring (current implementation doesn't support this) but if not I can use .predict and .set so its not big concern.
Or can I implement a method for register model easily to support burst operation.
I found this to help get you started:
http://forums.accellera.org/topic/716-uvm-register-model-burst-access/
The guy mentions using the optional 'extension' argument that read/write take. You could store the length of the burst length inside a container object (think int vs. Integer in Java) and then pass that as an argument when calling write() on the first register.
A rough sketch (not tested):
// inside your register sequence
uvm_queue #(int) container = new("container");
container.push_front(4);
start_reg.write(status, data, .extension(container));
// inside your adapter
function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
int burst_len = 1;
uvm_reg_item reg_item = get_item();
uvm_queue #(int) extension;
if ($cast(extension, reg_item.extension))
burst_len = extension.pop_front();
// do the stuff here based on the burst length
// ...
endfunction
I've used uvm_queue because there isn't any trivial container object in UVM.
After combining opinions provided by Tudor and links in the discussion, here is what works for adding burst operation to reg model.
This implementation doesn't show all the code but only required part for adding burst operation, I've tested it for write and read operation with serial protocols (SPI / I2C). Register model values are updated correctly as well as RTL registers are updated.
Create a class to hold data and burst length:
class burst_class extends uvm_object;
`uvm_object_utils (....);
int burst_length;
byte data [$];
function new (string name);
super.new(name);
endfunction
endclass
Inside register sequence (for read don't initialize data)
burst_class obj;
obj = new ("burstInfo");
obj.burst_length = 4; // replace with actual length
obj.data.push_back (data1);
obj.data.push_back (data2);
obj.data.push_back (data3);
obj.data.push_back (data4);
start_reg.read (status,...., .extension(obj));
start_reg.write (status, ...., .extension (obj));
After successful operation data values should be written or collected in obj object
In adapter class (reg2bus is updated for write and bus2reg is updated for read)
All the information about transaction is available in reg2bus except data in case of read.
adapter class
uvm_reg_item start_reg;
int burst_length;
burst_class adapter_obj;
reg2bus implementation
start_reg = this.get_item;
adapter_obj = new ("adapter_obj");
if($cast (adapter_obj, start_reg.extension)) begin
if (adapter_obj != null) begin
burst_length = adapter_obj.burst_length;
end
else
burst_length = 1; /// so that current implementation of adapter still works
end
Update the size of transaction over here according to burst_length and assign data correctly.
As for read bus2reg needs to be updated
bus2reg implementation (Already has all control information since reg2bus is always executed before bus2reg, use the values captured in reg2bus)
According to burst_length only assign data to object passed though extension in this case adapter_obj