Flash Memory Library
This library provides routines for accessing microcontroller's (internal) Flash memory.
On the dsPIC30/33 and PIC24, Flash memory is mapped to address space 3:2, which means that every 3 consecutive bytes of Flash have 2 consecutive address locations available. That is why mikroE's library allows data to be written to flash in two ways: "regular" and "compact". In the "regular" mode, which is used for word(16-bit) variables, the 3rd (un-addressable) flash memory byte remains unused. In the "compact" mode, which can be used for 1 byte-sized variables/arrays, all flash bytes are being used.
All dsPIC30/33 and PIC24 MCUs use the RTSP module to perform Read/Erase/Write operations on Flash memory. This, together with the internal structure of the Flash, imposes certain rules to be followed when working with Flash memory:
dsPIC30:
- Erasing can be done only in 32-instructions (64 addresses, 96 bytes) memory blocks. This means that the block start address should be a multiply of 64 (i.e. have 6 lower bits set to zero).
- Data is read and written in 4-instructions (8 addresses, 12 bytes) blocks.This means that the block start address should be a multiply of 8 (i.e. have 3 lower bits set to zero).
- On the dsPIC30s, 2 address locations are assigned on every 3 bytes of
(flash) program memory. Due to this specific and non-one-to-one address mapping,
the mikroC PRO for dsPIC30/33 and PIC24 offers two sets of Flash handling
functions: "regular" and "compact".
Using the "regular" set, the user can write one byte of data to a single address, which means that each byte of written data has its own address, but on every 2 written bytes one byte of Flash memory remains empty.
Using the "compact" set, every byte of Flash memory, including those non-addressable, is filled with data; this method can only be used for data organized in bytes.
The "compact" functions have_Compactas name suffix. - For run-time FLASH read/write, the dsPIC30's RTSP module is being used. It
organizes data into rows and panels. Each row contains write latches that can
hold 4 instructions (12 bytes). The number of panels varies from one dsPIC30 MCU
model to another. Because of that, the flash write sequence has been split into
several operations (
_Write_Init(), _Write_LoadLatch4(), _Write_DoWrite()), in order to be usable on all dsPICs.
PIC24 and dsPIC33:
- Erasing can be done only in 512-instructions (1024 addresses, 1536 bytes) memory blocks, which means that the block start address should be a multiply of 1024 (i.e. have 10 lower bits set to zero).
- Data is read and written in 64-instructions (128 addresses, 192 bytes) blocks.This means that the block start address should be a multiply of 128 (i.e. have 7 lower bits set to zero).
- On the dsPIC33 and PIC24s, 2 address locations are assigned on every 3 bytes
of (flash) program memory. Due to this specific and non-one-to-one address
mapping, the mikroC PRO for dsPIC30/33 and PIC24 offers two sets of Flash
handling functions: "regular" and "compact".
Using the "regular" set, the user can write one byte of data to a single address, which means that each byte of written data has its own address, but on every 2 written bytes one byte of Flash memory remains empty.
Using the "compact" set, every byte of Flash memory, including those non-addressable, is filled with data; this method can only be used for data organized in bytes.
The "compact" functions have_Compactas name suffix.
24F04KA201 and 24F16KA102 Family Specifics :
- These MCU's have their Flash memory organized into memory blocks of 32 instructions (96 bytes), unlike other PIC24 devices.
- Erasing can be done only in 32-instructions (64 addresses, 96 bytes) memory blocks, which means that the block start address should be a multiply of 64 (i.e. have 6 lower bits set to zero).
- Data is read and written in 32-instructions (64 addresses, 96 bytes) blocks. This means that the block start address should be a multiply of 64 (i.e. have 6 lower bits set to zero).
- Unlike other PIC24 devices, writing or erasing one block of data (32 instructions), is followed by erasing the memory block of the same size (32 instructions).
Library Routines
dsPIC30 Functions
- FLASH_Write_Block
- FLASH_Write_Compact
- FLASH_Write_Init
- FLASH_Write_Loadlatch4
- FLASH_Write_Loadlatch4_Compact
- FLASH_Write_DoWrite
PIC24 and dsPIC33 Functions
dsPIC30 Functions
FLASH_Erase32
| Prototype | void FLASH_Erase32(unsigned long address); |
|---|---|
| Description | Erases one block (32 instructions, 64 addresses, 96 bytes)from the program FLASH memory. |
| Parameters |
|
| Returns | Nothing. |
| Requires | Nothing. |
| Example | //--- erase the 32-instruction block, starting from address 0x006000 FLASH_Erase32(0x006000); |
| Notes | The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Block
| Prototype | void FLASH_Write_Block(unsigned long address, unsigned int *data_); |
|---|---|
| Description | Fills one writeable block of Flash memory (4 instructions, 8 addresses, 12 bytes) in the "regular" mode. Addresses and data are being mapped 1-on-1. This also means that 3rd byte of each program location remains unused. |
| Parameters |
|
| Returns | Nothing. |
| Requires | The block to be written to must be erased first, either from the user code (through the RTSP), or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
| Example | unsigned long flash_address = 0x006000;
unsigned int Buffer[4] = {'A', 'B', 'C', 'D'};
...
FLASH_Write_Block(flash_address, Buffer);
|
| Notes | The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Compact
| Prototype | void FLASH_Write_Compact(unsigned long address, void *data_, unsigned bytes); |
|---|---|
| Description | Fills a portion of Flash memory using the dsPIC30 RTSP module, in the "compact" manner. In this way, several blocks of RTSP's latch can be written in one pass. One latch block contains 4 instructions (8 addresses, 12 bytes). Up to 8 latch blocks can be written in one round, resulting in a total of 8*12 = 96 bytes. This method uses all available bytes of the program FLASH memory, including those that are not mapped to address space (every 3rd byte). |
| Parameters |
|
| Returns | Nothing. |
| Requires | The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
| Example | unsigned long flash_address = 0x006000; char Buffer[] = "supercalifragillisticexpialidotious"; ... FLASH_Write_Compact(flash_address, Buffer, 36); |
| Notes | The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Init
| Prototype | void FLASH_Write_Init(unsigned long address, void *data_); |
|---|---|
| Description | Initializes RTSP for write-to-FLASH operation. |
| Parameters |
|
| Returns | Nothing. |
| Requires | The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
| Example | //--- Initializes the Flash to be written, starting from address 0x006100, the data is located at *pv1 void *pv1; ... FLASH_Write_Init(0x006100, pv1); |
| Notes | The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Loadlatch4
| Prototype | void FLASH_Write_Loadlatch4(); |
|---|---|
| Description | Loads the current RTSP write latch with data (4 instructions, 8 addresses, 12 bytes). The data is filled in the "regular" mode. |
| Parameters | None. |
| Returns | Nothing. |
| Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU.
Please note that block size that is to be erased is different from the one that
can be written with this function! This function is used as a part of the Flash write sequence, therefore the FLASH_Write_Init function must be called before this one. This function can be called several times before commiting the actual write-to-Flash operation FLASH_Write_DoWrite. This depends on the organization of the RTSP module for the certain dsPIC30. Please consult the Datasheet for particular dsPIC30 on this subject. |
| Example | //--- writes data from an array, in "regular" manner
unsigned int iArr[16] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e', 'k'};
void * pv1;
...
pv1 = iArr;
FLASH_Write_Init(0x006100, pv1);
FLASH_Write_Loadlatch4();
FLASH_Write_Loadlatch4();
FLASH_Write_DoWrite();
|
| Notes | None. |
FLASH_Write_Loadlatch4_Compact
| Prototype | void FLASH_Write_Loadlatch4_Compact(); |
|---|---|
| Description | Loads the current RTSP write latch with data (4 instructions, 8 addresses, 12 bytes). The data is filled in the "compact" mode. |
| Parameters | None. |
| Returns | Nothing. |
| Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU.
Please note that block size that is to be erased is different from the one that
can be written with this function! This function is used as a part of the Flash write sequence, therefore the FLASH_Write_Init function must be called before this one. This function can be called several times before committing actual write-to-Flash operation FLASH_Write_DoWrite. This depends on the organization of the RTSP module for the certain dsPIC30. Please consult the Datasheet for particular dsPIC30 on this subject. |
| Example | //--- writes data from an array of char, in "compact" manner char cArr[] = "supercalifragillisticexpialidotious"; //35+1 bytes void * pv1; ... pv1 = cArr; FLASH_Write_Init(0x006000, pv1); //init FLASH_Write_Loadlatch4_Compact(); //12 bytes FLASH_Write_Loadlatch4_Compact(); //12 bytes FLASH_Write_Loadlatch4_Compact(); //12 bytes FLASH_Write_DoWrite(); //commit write |
| Notes | None. |
FLASH_Write_DoWrite
| Prototype | void FLASH_Write_DoWrite(); |
|---|---|
| Description | Commits the FLASH write operation. |
| Parameters | None. |
| Returns | Nothing. |
| Requires |
The block to be written to must be erased first, either from the user code FLASH_Erase32, or during the programming of MCU.
Please note that block size that is to be erased is different from the one that
can be written with this function! This function is used as a part of the Flash write sequence, therefore FLASH_Write_Init and certain number of FLASH_Write_Loadlatch4 or FLASH_Write_Loadlatch4_Compact function calls must be made before this one. This function is to be called once, at the and of the FLASH write sequence. |
| Example | //--- writes data from an array, in "regular" manner
unsigned int iArr[16] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e', 'k'};
void * pv1;
...
pv1 = iArr;
FLASH_Write_Init(0x006100, pv1);
FLASH_Write_Loadlatch4();
FLASH_Write_Loadlatch4();
FLASH_Write_DoWrite();
|
| Notes | None. |
FLASH_Read4
| Prototype | unsigned int* FLASH_Read4(unsigned long address, unsigned int *write_to); |
|---|---|
| Description |
Reads one latch row (4 instructions, 8 addresses) in the "regular" mode. |
| Parameters |
|
| Returns | Starting address of RAM buffer for storing read data. |
| Requires | Nothing. |
| Example | //--- reads 8 bytes (4 words) from location 0x006000 and stores it to *pv1; unsigned int *pv1; ... FLASH_Read4(0x006000, pv1); |
| Notes | The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read4_Compact
| Prototype | void* FLASH_Read4_Compact(unsigned long address, void *write_to); |
|---|---|
| Description | Reads one latch row (4 instructions, 8 addresses) in the "compact" mode. |
| Parameters |
|
| Returns | Starting address of RAM buffer for storing read data. |
| Requires | Nothing. |
| Example | //--- reads 12 bytes (4 words) from location 0x006000 and stores it to *pv1; unsigned int *pv1; ... FLASH_Read4_Compact(0x006000, pv1); |
| Notes | The user should take care of the address alignment (see the explanation at the beginning of this page). |
PIC24 and dsPIC33 Functions
FLASH_Erase
| Prototype | void FLASH_Erase(unsigned long address); |
|---|---|
| Description | Erases one block (512 instructions, 1024 addresses, 1536 bytes) from the program FLASH memory. |
| Parameters |
|
| Returns | Nothing. |
| Requires | Nothing. |
| Example | //--- erase the flash memory block, starting from address 0x006400 unsigned long flash_address = 0x006400; ... FLASH_Erase(flash_address); |
| Notes | The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write
| Prototype | void FLASH_Write(unsigned long address, unsigned int *data_); |
|---|---|
| Description | Fills one writeable block of Flash memory (64 instructions, 128 addresses, 192 bytes) in the "regular" mode. Addresses and data are being mapped 1-on-1. This also means that 3rd byte of each program location remains unused. |
| Parameters |
|
| Returns | Nothing. |
| Requires | The block to be written to must be erased first, either from the user code (through the RTSP), or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
| Example | unsigned int iArr[64] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e', 'k', 't', 'r', 'o', 'n', 'i', 'k', 'a'};
void * pv1;
...
pv1 = iArr;
FLASH_Write(0x006500, pv1);
|
| Notes | The user should take care about the address alignment (see the explanation at the beginning of this page). |
FLASH_Write_Compact
| Prototype | void FLASH_Write_Compact(unsigned long address, char *data_); |
|---|---|
| Description | Fills a portion of Flash memory (64 instructions, 128 addresses, 192 bytes) using the dsPIC33 and PIC24s RTSP (Run Time Self Programming) module, in the "compact" manner. This method uses all available bytes of the program FLASH memory, including those that are not mapped to address space (every 3rd byte). |
| Parameters |
|
| Returns | Nothing. |
| Requires | The block to be written to must be erased first, either from the user code (FLASH_Erase), or during the programming of MCU. Please note that block size that is to be erased is different from the one that can be written with this function! |
| Example | char cArr[] = "supercalifragillisticexpialidotiousABCDEFGHIJKLMNOPRSTUVWXYZ1234"; void * pv1; ... pv1 = cArr; FLASH_Write_Compact(0x006400, pv1); |
| Notes | The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read
| Prototype | unsigned int* FLASH_Read(unsigned long address, unsigned int *write_to, unsigned NoWords); |
|---|---|
| Description | Reads required number of words from the flash memory in the "regular" mode. |
| Parameters |
|
| Returns | Address of RAM buffer for storing read data. |
| Requires | |
| Example | unsigned Buffer[64]; unsigned long start_address = 0x6500; ... FLASH_Read(start_address, Buffer, 10); |
| Notes | The user should take care of the address alignment (see the explanation at the beginning of this page). |
FLASH_Read_Compact
| Prototype | void *FLASH_Read_Compact(unsigned long address, void *write_to, unsigned NoBytes); |
|---|---|
| Description | Reads required number of bytes from the flash memory in the "compact" mode. |
| Parameters |
|
| Returns | Address of RAM buffer for storing read data. |
| Requires | |
| Example | char Buffer[64]; unsigned long start_address = 0x6500; ... FLASH_Read_Compact(start_address, Buffer, 10); |
| Notes | The user should take care of the address alignment (see the explanation at the beginning of this page). |
Library Example
In this example written for dsPIC30F4013, various read/write tecniques to/from the on-chip FLASH memory are shown. Flash memory is mapped to address space 3:2, meaning every 3 consecutive bytes of Flash have 2 consecutive address locations available.
That is why mikroE's library allows data to be written to Flash in two ways: 'regular' and 'compact'. In 'regular' mode, which is used for variables that are size of 2 bytes and more, the 3rd (un-addressable) byte remains unused.
In 'compact' mode, which can be used for 1 byte-sized variables/arrays, all bytes of flash are being used.
unsigned int iArr[8] = {'m', 'i', 'k', 'r', 'o', 'E', 'l', 'e'};
char cArr[] = "mikroElektronika Flash example";
char cArr2[40];
void * pv1;
unsigned bb;
void main() {
unsigned i;
pv1 = cArr;
/*
This is what FLASH_Write_Compact() does 'beneath the hood'
*
FLASH_Write_Init(0x006000, pv1);
FLASH_Write_Loadlatch4_Compact();
FLASH_Write_Loadlatch4_Compact();
FLASH_Write_Loadlatch4_Compact();
FLASH_Write_DoWrite();
*/
//--- erase the block first
FLASH_Erase32(0x006000);
//--- write compact format to flash
FLASH_Write_Compact(0x006000, pv1, 36);
//--- read compact format
pv1 = cArr2;
FLASH_Read4_Compact(0x006000, pv1);
pv1 += 12;
FLASH_Read4_Compact(0x006008, pv1);
pv1 += 12;
FLASH_Read4_Compact(0x006010, pv1);
pv1 += 12;
*pv1 = 0; //termination
//--- show what has been written
i = 0;
UART1_Init(9600);
// UART1_Write_Text("Start");
UART1_Write(10);
UART1_Write(13);
while(cArr2[i]) {
bb = cArr2[i++];
UART1_Write(bb);
}
//--- now for some non-compact flash-write
pv1 = iArr;
//--- erase the block first
FLASH_Erase32(0x006100);
FLASH_Write_Init(0x006100, pv1);
FLASH_Write_Loadlatch4();
FLASH_Write_Loadlatch4();
FLASH_Write_DoWrite();
}



Also note that a DOF has its limitations, known as the configuration
space. Not all joints can swivel 360 degrees! A joint has some max angle
restriction. For example, no human joint can rotate more than about 200 degrees.
Limitations could be from wire wrapping, actuator capabilities,
Now lets assume that all joints rotate a maximum of 180 degrees,
because most
Now rotating that by the base joint another 180 degrees to get 3D, we have
this workspace image. Remember that because it uses servos, all joints are
limited to a max of 180 degrees. This creates a workspace of a shelled
semi-sphere (its a shape because I said so).
If you change the link lengths you can get very different sizes of
workspaces, but this would be the general shape. Any location outside of this
space is a location the arm cant reach. If there are objects in the way of the
arm, the workspace can get even more complicated.
Here are a few more robot workspace examples:

Assume that the base is located at x=0 and y=0. The first step would be to
locate x and y of each joint.
Joint 0 (with x and y at base equaling 0):
There is the possibility of zero solutions. Maybe the location is
outside the workspace, or maybe the point within the workspace must be gripped
at an impossible angle.
Singularities, a place of infinite acceleration, can blow up equations
and/or leave motors lagging behind (motors cant achieve infinite acceleration).
And lastly, exponential equations take forever to calculate on a
Suppose your robot arm has objects within its workspace, how does the
arm move through the workspace to reach a certain point? To do this, assume your
robot arm is just a simple mobile robot navigating in 3D space. The end effector
will traverse the space just like a mobile robot, except now it must also make
sure the other joints and links do not collide with anything too. This is
extremely difficult to do . . .
What if you want your robot end effector to draw straight lines with a
pencil? Getting it to go from point A to point B in a straight line is
relatively simple to solve. What your robot should do, by using inverse
kinematics, is go to many points between point A and point B. The final motion
will come out as a smooth straight line. You can not only do this method with
straight lines, but curved ones too. On expensive professional robotic arms all
you need to do is program two points, and tell the robot how to go between the
two points (straight line, fast as possible, etc.). For further reading, you
could use the
Which method is better? There are many deciding factors. Usually you want
straight lines when the object the arm moves is really heavy, as it requires the
momentum change for movement (
Keep the heaviest components, such as motors, as close to the robot arm base
as possible. It might be a good idea for the middle arm joint to be
chain/belt driven by a motor located at the base (to keep the heavy motor on the
base and off the arm).
The sagging problem is even worse when the arm wobbles between stop-start
motions. The solve this, implement a
Haptic sensing is a little different in that there is a human in the
loop. The human controls the robot arm movements remotely. This could be done by
wearing a special glove, or by operating a miniature model with position
sensors. Robotic arms for amputees are doing a form of haptic sensing. Also to
note, some robot arms have feed back sensors (such as touch) that gets directed
back to the human (vibrating the glove, locking model joints, etc.).
Tactile sensing (sensing by touch) usually involves
Try this. Close your eyes, and put both of your hands in your lap. Now
keeping your eyes closed, move your hand slowly to reach for your
computer mouse. Do it!!!! You will see why soon . . . Now what will happen is
that your hand will partially miss, but at least one of your fingers will touch
the mouse. After that finger touches, your hand will suddenly re-adjust its
position because it now knows exactly where that mouse is. This is the benefit
of tactile sensing - no precision


