Ok, here the deal.
The need is to develop a timer, faster, capable to control up to 16 UV fluorescent bulbs.
Up to 2 hours, 1 second precision, display to show the countdown and menu' management, digital encoder for input, pushbuttons/LEDs.
It can be done in thousands ways, but this time I'll try to put it together using Energia and a BIG help from Roberto.
Translate
Saturday, November 14, 2015
Wednesday, November 4, 2015
Embedded RPOf
The next thing to do about the RPOf is to embed it in a piggy back board over the Raspberry Pi.
The Raspberry Pi GPIO connector has both the 3.3V and 5V rail available, so to have a more compact system, embedding the RPOf on the "shield" connected to the Raspberry Pi, can helps to reduce the space and number of boards.
The Raspberry Pi GPIO connector has both the 3.3V and 5V rail available, so to have a more compact system, embedding the RPOf on the "shield" connected to the Raspberry Pi, can helps to reduce the space and number of boards.
Friday, October 30, 2015
Working on the iRis project
[To be updated !]
A step-by-step guide to work on git for the iRis project.
If you are new on git and github, read this article first.
The iRis project is on github, so if somebody wants to join it, or just follow the progress, can clone the git repo for iRis.
A step-by-step guide to work on git for the iRis project.
If you are new on git and github, read this article first.
The iRis project is on github, so if somebody wants to join it, or just follow the progress, can clone the git repo for iRis.
Working on RPOf project
Here a step-by-step guide to work on git for the RPOf project.
If you are new on git and github, read this article first.
If you are new on git and github, read this article first.
Working on my projects
Here a step-by-step guide to work on git for some projects I maintain.
This guide assumes:
The most important thing to remember working with git, is that normally ALL the operations are LOCAL to your machine !
Only few specific and explicitly called operations operate on a remote server, in our case, github.
Specifically :
The first time we want to clone the project from github.
How we do that ?
First of all we must have git on our machine.
So if you don't already installed it, open a terminal and type :
(note, I'm using for this article, the git version 1.9.1 on a Ubuntu 14.04 LTS)
After the installation, is better to set it up with some basic info :
I'm not sure if is valid for every type of operation, but it is possible github will require a SSH key in order to clone/update a project.
In that case I strongly recommend to follow this brief tutorial about how to generate and deploy an ssh key with github.
In case you are not interested to collaborate to the project but wants to have the project on your machine, or in case you don't want to install git or generate SSH keys, from github is possible to download the project as a zip file.
All these operations are LOCAL to your machine !
If you are a registered collaborator to the project (ask me), then you should be able to "push" your modifications in the github with:
git push
In order to reduce the conflict between developer, I suggest this protocol:
This guide assumes:
- you like Linux, you USE Linux
- you know how to work with the terminal
- the instructions are based on Ubuntu, but they should be easily used on other systems.
The main difference could be the application to install code. apt-get for Ubuntu, yum for Red Hat/CentOS, ecc. - you know how to set up a cross compiler for different microcontroller under Linux
Introduction
The most important thing to remember working with git, is that normally ALL the operations are LOCAL to your machine !
Only few specific and explicitly called operations operate on a remote server, in our case, github.
Specifically :
- The first time, when we clone the project from github
- Every time we want to update our code from github
- Every time we want to save our work on github
First time
git Installation
How we do that ?
First of all we must have git on our machine.
So if you don't already installed it, open a terminal and type :
- sudo apt-get update
- sudo apt-get install git
(note, I'm using for this article, the git version 1.9.1 on a Ubuntu 14.04 LTS)
After the installation, is better to set it up with some basic info :
- git config --global user.name "your name"
- git config --global user.email "youremail@domain.com"
- git config --list will show the configuration for your git
For example :
git config --global user.name "John Smith"
git config --global user.email "jsmith@mystery.com"
I'm not sure if is valid for every type of operation, but it is possible github will require a SSH key in order to clone/update a project.
In that case I strongly recommend to follow this brief tutorial about how to generate and deploy an ssh key with github.
At this point you are ready to clone the project from github !
Clone a project
Cloning is the act that duplicate on your hard drive what is present in a remote git repository, in this case github.
The cloning is strongly suggested in case you want to collaborate to the project.
Cloning the project recreate on your local machine the project and it's history and allows to merge it back on github if you do modifications.
The cloning is strongly suggested in case you want to collaborate to the project.
Cloning the project recreate on your local machine the project and it's history and allows to merge it back on github if you do modifications.
First of all create or go on a directory that will host the project.
For example, create a directory called SteveProjects on your home environment :
- cd ~
- mkdir SteveProjects
- cd SteveProjects
Now is possible to use git to clone a project, with the command :
- git clone URL_repository
That's it !
On your directory Projects, will exist a directory called as the project name, containing the project.
Download a project
In case you are not interested to collaborate to the project but wants to have the project on your machine, or in case you don't want to install git or generate SSH keys, from github is possible to download the project as a zip file.
Update project
Now that you have the project on your machine, to keep it updated is even easier.
Simply go in the project directory and issue the command : git pull
- cd ~/Projects/project_name
- git pull
That's it ! If the code on the github is changed, it will be updated on your machine
If you want to collaborate to a project, you can modify the code on your machine, and keep track of the modifications locally, using git.
Issuing the command git status returns the status of the modifications made to the code.
Every time you modify a file, git status will indicate a modification.
Every time you will have to add it with:
git add file_name
git add * will add all the modified files.
Then it will be possible to commit the file with:
git commit file_name
Working on the project
Commit the project
If you want to collaborate to a project, you can modify the code on your machine, and keep track of the modifications locally, using git.
Issuing the command git status returns the status of the modifications made to the code.
Every time you modify a file, git status will indicate a modification.
Every time you will have to add it with:
git add file_name
git add * will add all the modified files.
Then it will be possible to commit the file with:
git commit file_name
If you are a registered collaborator to the project (ask me), then you should be able to "push" your modifications in the github with:
git push
Working protocol
In order to reduce the conflict between developer, I suggest this protocol:
- Clone the project
git clone URL_of_github_project - Create a branch
git checkout -b branch_name - Work on your modifications, add and commit regularly
- When is time to push the modifications:
git push origin branch_name - If allowed, merge the branch on the master.
Tuesday, October 13, 2015
iRis project - an introduction
The purpose of the iRis project is to have a "head" for medical training purpose related to eyes illness.
Basically the idea is to build a "eyes simulator" capable to react to the light like an eye does, in order to simulate different types of illness retina/nerve related.
Basically the idea is to build a "eyes simulator" capable to react to the light like an eye does, in order to simulate different types of illness retina/nerve related.
Friday, August 14, 2015
Cooling the server area
Problem, cool down the server area.
The server is placed under a stair and the server area is insulated.
The area is in contact with the garage and the laundry room and of course the garage of course is not an insulated area, but the laundry it is.
Thus the idea : drill a hole in the stairs and connect a fan to aspire the fresh air from the laundry room.
The server is placed under a stair and the server area is insulated.
The area is in contact with the garage and the laundry room and of course the garage of course is not an insulated area, but the laundry it is.
Thus the idea : drill a hole in the stairs and connect a fan to aspire the fresh air from the laundry room.
Tuesday, August 11, 2015
MSP430 - Energia and Grove
I do have few Arduino around.
Like many people I bought some of them because ... well, I don't know, I guess at the time it was the news, to see what it is.
And I didn't like it much.
Saturday, August 8, 2015
MSP430 - I2C library
There are many different library out there to handle I2C with the MSP430.
Some of the libraries are also "official", from TI.
I found a nice and simple C library to handle the I2C with USI is on github and apparently is easy to deploy and use.
This article contains some notes about how to deploy and use the library, closing some missing practical information.
Let's start with ... the hardware.
The library was originally developed and tested on an MSP430g2452.
It surely can work on any MSP430 family member that has a USI, that's was anyway my initial intent.
I tried to use an MSP430f2013 but in the end I opted to buy some MSP430g2452 because the 2013 doesn't have enough memory (only 2K ROM) to handle protocol and the rest of the code needed for a project.
The MSP430g2452 has 8K ROM.
After choosing the microcontroller, the attention was concentrated on the I/O pin to use.
Note ! Initially I'm experiment using a Launchpad.
The library expects to use the USI pins, i.e. the P1.6 for the SCL and the P1.7 for the SDA.
Apparently there is NO need to bother with the I/O ports to inform the MSP430 that the 2 pins are dedicated to the USI in I2C mode.
Is enough to program the USI control register to do that, and that is taken care in the i2c_init function provided by the library.
Important !!! The P1.6 on the Launchpad is connected to the green LED !
Remove the jumper on that LED in order to have something working !
The library presumably is written for IAR or other commercial system.
In order to compile it with Mspgcc few modifications are necessary.
I also fixed a bug that was preventing the library to read more than 8 bit at a time.
In the usi_i2c.c file, in the interrupt function Usi_txrx change the highlighted line :
..................................................................
..................................................................
case I2C_RECEIVED_DATA: // received data, send ACK/NACK
*i2c_receive_buffer = USISRL;
i2c_receive_buffer++;
USICTL0 |= USIOE; // SDA = output
if(i2c_sequence_length > 1) {
// If this is not the last byte
USISRL = 0x00; // ACK
..................................................................
..................................................................
The library has only three "public" functions and act as Master.
Let see how to use it.
The first public function is called i2c_init and like the name imply, is used to initialize the USI and set up the MSP430 to use it.
It must be called once, preferably after other basic I/O initializations happens.
After that, the "system" should be able to send out I2C messages.
Example:
i2c_init(USIDIV_5, USISSEL_2);
The first parameter determine the division applied to the input clock.
USIDEV_0 divide by 1, USIDEV_1 divide by 2, USIDEV_2 divide by 4 and so on (see MSP430 Family user guide - USICKCTL register).
The second parameter determine the source of the clock (see MSP430 Family user guide - USICKCTL register).
In the example above the source for the clock is the SMCLK divided by 32.
This function returns TRUE (1) or FALSE (0) to indicate if a transaction is running.
The I2C messages are sent via interrupt so it is possible that the main program is ready to send another sequence when the system is still handling the previous sequence.
So before to perform any request, better to see if the system is ready to accept it.
Example:
if(i2c_done())
i2c_send_sequence((uint16_t *)seq1, 2, (uint8_t *)recseq, 0);
or
while(!i2c_done());
Strongly suggested to use it to prevent to start a sequence when another one is still running.
Simply put, this function can send and receive information via I2C using a "sequence".
The sequence is a series of word and commands.
i2c_usi.h defines two commands :
The sequences to send depends strictly to a specific component so there is no a generic suggestion if not to carefully read the datasheet of the component.
Some of the libraries are also "official", from TI.
I found a nice and simple C library to handle the I2C with USI is on github and apparently is easy to deploy and use.
This article contains some notes about how to deploy and use the library, closing some missing practical information.
Let's start with ... the hardware.
Hardware
The library was originally developed and tested on an MSP430g2452.
It surely can work on any MSP430 family member that has a USI, that's was anyway my initial intent.
I tried to use an MSP430f2013 but in the end I opted to buy some MSP430g2452 because the 2013 doesn't have enough memory (only 2K ROM) to handle protocol and the rest of the code needed for a project.
The MSP430g2452 has 8K ROM.
After choosing the microcontroller, the attention was concentrated on the I/O pin to use.
Note ! Initially I'm experiment using a Launchpad.
The library expects to use the USI pins, i.e. the P1.6 for the SCL and the P1.7 for the SDA.
Apparently there is NO need to bother with the I/O ports to inform the MSP430 that the 2 pins are dedicated to the USI in I2C mode.
Is enough to program the USI control register to do that, and that is taken care in the i2c_init function provided by the library.
Important !!! The P1.6 on the Launchpad is connected to the green LED !
Remove the jumper on that LED in order to have something working !
Software
Compile it
The library presumably is written for IAR or other commercial system.
In order to compile it with Mspgcc few modifications are necessary.
- Remove the specific include of the msp430g2452 header from usi_i2c.c
- Add the generic include of msp430 in the usi_i2c.h
- Remove the include of the stdint.h header from usi_i2c.c and move in the usi_i2c.h
- Change the interrupt declaration, from:
#pragma vector = USI_VECTOR
__interrupt void USI_TXRX(void)
{
switch(__even_in_range(i2c_state,12))
to
__attribute__((__interrupt__(USI_VECTOR)))
void Usi_txrx (void){ switch(__even_in_range(i2c_state,12)) - Move the inline function i2c_done() from the header file (usi_i2c.h) into the module (usi_i2c.c) and leave a function prototype for that function in the usi_i2c.h header file
With these modifications I was able to compile the library using mspgcc.
I also fixed a bug that was preventing the library to read more than 8 bit at a time.
In the usi_i2c.c file, in the interrupt function Usi_txrx change the highlighted line :
..................................................................
..................................................................
case I2C_RECEIVED_DATA: // received data, send ACK/NACK
*i2c_receive_buffer = USISRL;
i2c_receive_buffer++;
USICTL0 |= USIOE; // SDA = output
if(i2c_sequence_length > 1) {
// If this is not the last byte
USISRL = 0x00; // ACK
..................................................................
..................................................................
with
..................................................................
..................................................................
case I2C_RECEIVED_DATA: // received data, send ACK/NACK
*i2c_receive_buffer = USISRL;
i2c_receive_buffer++;
USICTL0 |= USIOE; // SDA = output
if(i2c_sequence_length > 0) { // TheFwGuy MOD !!!
// If this is not the last byte
USISRL = 0x00; // ACK
..................................................................
..................................................................
..................................................................
case I2C_RECEIVED_DATA: // received data, send ACK/NACK
*i2c_receive_buffer = USISRL;
i2c_receive_buffer++;
USICTL0 |= USIOE; // SDA = output
if(i2c_sequence_length > 0) { // TheFwGuy MOD !!!
// If this is not the last byte
USISRL = 0x00; // ACK
..................................................................
..................................................................
Use it
The library has only three "public" functions and act as Master.
Let see how to use it.
i2c_init
The first public function is called i2c_init and like the name imply, is used to initialize the USI and set up the MSP430 to use it.
It must be called once, preferably after other basic I/O initializations happens.
After that, the "system" should be able to send out I2C messages.
Example:
i2c_init(USIDIV_5, USISSEL_2);
The first parameter determine the division applied to the input clock.
USIDEV_0 divide by 1, USIDEV_1 divide by 2, USIDEV_2 divide by 4 and so on (see MSP430 Family user guide - USICKCTL register).
The second parameter determine the source of the clock (see MSP430 Family user guide - USICKCTL register).
In the example above the source for the clock is the SMCLK divided by 32.
i2c_done
This function returns TRUE (1) or FALSE (0) to indicate if a transaction is running.
The I2C messages are sent via interrupt so it is possible that the main program is ready to send another sequence when the system is still handling the previous sequence.
So before to perform any request, better to see if the system is ready to accept it.
Example:
if(i2c_done())
i2c_send_sequence((uint16_t *)seq1, 2, (uint8_t *)recseq, 0);
or
while(!i2c_done());
Strongly suggested to use it to prevent to start a sequence when another one is still running.
i2c_send_sequence
This is the main function and the most complex to handle.Simply put, this function can send and receive information via I2C using a "sequence".
The sequence is a series of word and commands.
i2c_usi.h defines two commands :
- I2C_RESTART
- I2C_READ
The function has these inputs:
- sequence
sequence is a pointer to an array containing the I2C operation sequence that should be performed.
It can include any number of writes, restarts and reads.
The sequence is composed of uint16_t, not uint8_t elements.
This is because the need to support out-of-band signalling of I2C_RESTART and I2C_READ operations, while still passing through 8-bit data.
The sequence uses the Bus Pirate I2C convention.
The address must be prepared manually, adding the R/W bit.
The address is prepared shifting the 7-bit I2C address to the left and add the R/W bit (0 to write, 1 to read).
The examples above communicate with a device whose I2C address is 0x1c, which shifted left gives 0x38.
For reads we use 0x39, which is (0x1c<<1)|1.
So for example, to write at the address 0x39, the sequence would be:
- 0x39 << 1 = 0x72
And to read from the address 0x39:- (0x39 << 1) | 1 = 0x73
- sequence length
sequence_length is the number of sequence elements (not bytes).
Sequences of arbitrary (well, 32-bit) length are supported. - received data
received_data should point to a buffer that can hold as many bytes as there are I2C_READ operations in the sequence.
If there are no reads, 0 can be passed, as this parameter will not be used. - wake up sr bits
Used if you want to use the MSP430 in low power mode.
Building sequences
The sequences to send depends strictly to a specific component so there is no a generic suggestion if not to carefully read the datasheet of the component.
Thursday, July 23, 2015
My quick'ndirty installation of ZeroMq
ZeroMQ supports different languages and thus allow an easy interprocess data exchange between different programs.
For example a C program can easily exchange data with a Python or Java program.
Install ZeroMQ
To install ZeroMQ, is necessary to compile the source code and generate the library.To do so, under ubuntu :
- sudo apt-get install build-essential
- sudo apt-get install libtool
- sudo apt-get install automake
- sudo apt-get install autoconf
- sudo apt-get install uuid-dev
- Download the tarball for the libsodium from the Libsodium website
- Extract the tarball in a directory
- go in the directory
- ./configure
- make
- sudo make install
- Download the tarball from the ZeroMQ website
- extract the tarball in a directory
- go in the directory
- ./configure
- make
- sudo make install
On some systems is better to run :
sudo ldconfig to update the system library cache, otherwise it is requested a reboot of the machine.
Install Czmq
In order to bind the library with the C language is necessary to compile the library Czmq- git clone https://github.com/zeromq/czmq
- cd czmq
- ./autogen.sh
- ./configure
- make
- sudo make install
- sudo ldconfig
Use ZeroMQ in your code
Usually the libraries by default are placed in /usr/local/lib.
In order to use ZeroMQ in a project is enough to add to the linker phase the two main libraries, zeroMQ and the binding one.
Usually the name is the name of the library minus the "lib" part and the extension.
So for example, if the zeroMQ main library is called libzmq.so.3, the library name to be used in the linker will be zmq.
For example in a makefile :
LIB0MQ = -l zmq -l czmq # define variable LIB0MQ containing the libraries directive
................
................
CC = gcc $(CFLAGS) -c
CC1 = gcc $(CFLAGS)
LD = $(LIB0MQ)
AS = as $(AFLAGS)
Then in the main preparation of the code :
projectName: $(projectName_objs)
$(CC1) -o $(APPNAME) $(projectName_objs) $(LD)
Cross compile for ARM
To cross compile for ARM, be sure to have installed a ARM toolchain other the packages described above, and when ready to compile ZeroMQ, starts with :- ./configure --host=arm-none-linux-gnueabi
- make
Compile the examples
To compile the examples is possible to use the build script provided with the examples.
However it can be overshooting.
I suggest to use this approach :
- copy the examples in a local directory
- run : gcc -Wall -g name_example.c -lzmq -o name_example
Sunday, April 26, 2015
Monitoring health data - populating Food tables
This article continue the discussion about the building of the system to collect my health numbers.
The index in the cell A2 use the Hash macro (it is implied the third Party Hash macro is installed):
=TEXTHASH(CONCATENATE(B2,L2,F2),"MD5")
The goal is to have a unique index and to do so the hash is calculated using the name of the food (B2), the value in carbs (F2) and the brand (L2).
The field in the table are mostly following the SQL table structure (see Monitoring health data - an improvement).
For extra info there are these fields:
Insert into t_food_type values ("ce7993e549b4d010c825766dfd034a99","Pork Patties",2,"patty",2,270,11,24,500,0,"Jimmy Dean","");
Insert into t_food_type values ("981a21f5a752cad048a834b9fd6cd258","Cooked Ham",4,"slices",1,60,8,2,580,0,"Land O'Frost","");
Insert into t_food_type values ("1a52451ea65def964ddb3c2be50811ce","Big Cup Noodles Homestyle Beef Flavor Ramen Noodle",1,"1/2 container",24,190,3,8,760,0,"Nissin","");
Insert into t_food_type values ("74ccbb6a8f0e507375ca5f727074a4e1","Texas Style Angus Beef Chili with Black Beans Soup",1,"cup",21,210,15,5,790,0,"Campbell","");
Insert into t_food_type values ("76d5f224ea4a78e3d737caa4eba0d1e","iesta Chicken Lime Tortilla Soup with White Meat Chicken",1,"cup",13,110,9,1.5,790,0,"Campbell","");
After the table is manually populated, we end up with a list of insert capable to fill up the T_FOOD_TYPE table.
The Calculated carbs and Calculated Salt are populated using data from the previous table.
Calculated carbs is :
=VLOOKUP(D2,'Food type'.$A$2:$M$156, 6, 0)*F2
The meaning is to look in the all previous tab (Food type) of the spreadsheet for the FoodIndex key, retrieve the number of carbs per serving and multiply for the number of serving (field Servings on this tab).
Similarly for the Calculated salt :
=VLOOKUP(D2,'Food type'.$A$2:$M$156, 10, 0)*F2
The meaning is to look in the all previous tab (Food type) of the spreadsheet for the FoodIndex key, retrieve the number of mg of salt per serving and multiply for the number of serving (field Servings on this tab).
Just to have a quick idea about the amount of salt of the selected food.
The Index is an hash key using the Date Meal, the FoodIndex and the Food name fields.
Insert into t_food values (84280b208c8c61a7aab5c4be5fb25385, str_to_date('12/29/14', "%m/%d/%Y"), "Breakfast", "ac118ebecb401ae2e9fe42b8f7b1da8c", 2);
Insert into t_food values (16df74f3237c526a71186884b0cd7aa1, str_to_date('12/29/14', "%m/%d/%Y"), "Breakfast", "254a86d2153bfbc149f51d63c7113952", 1);
Insert into t_food values (532061254f4761e69bcf627c4916f3c2, str_to_date('12/29/14', "%m/%d/%Y"), "Lunch", "1b4f22d0d92b9185406cf6d815fd2c4c", 1);
Insert into t_food values (34c6041c3126488e599aa467e8a0d4de, str_to_date('12/29/14', "%m/%d/%Y"), "Lunch", "af3a803a27460603422bf47322ba6d4", 2);
Insert into t_food values (532061254f4761e69bcf627c4916f3c2, str_to_date('12/29/14', "%m/%d/%Y"), "Dinner", "1b4f22d0d92b9185406cf6d815fd2c4c", 2);
....................................................................
....................................................................
There are already many data stored in LibreOffice Calc tables and other LibreOffice documents.
Because of that when/where possible macro will be used to generate the mySQL commands to populate the tables.
Because of that when/where possible macro will be used to generate the mySQL commands to populate the tables.
Populate T_FOOD_TYPE
Populating this table it requires more work because it is necessary to find the information about each specific food used. In order to simplify the input mechanism, a new spreadsheet that collect the information to be put in the database, is created.
Unfortunately there is no easy way to populate the spreadsheet, i.e. it must be done manually, copying the data from the existing LibreOffice word documents as described in the Monitoring health data - my way #2 article.
Unfortunately there is no easy way to populate the spreadsheet, i.e. it must be done manually, copying the data from the existing LibreOffice word documents as described in the Monitoring health data - my way #2 article.
Let's examine the spreadsheet used to format the insert statement.
The spreadsheet has two tabs:
- Food type
- Food
The Food type tab, is structured as the database, raw.
A hash key is prepared as index, using the Food name, the brand and the number of carbs.
This should allow to generate a unique key for the each record.
A hash key is prepared as index, using the Food name, the brand and the number of carbs.
This should allow to generate a unique key for the each record.
Here the fields of the tab:
Index (food type) | Name | 1 Serving | Serving unit | Serv X cont | Carbs | Calories | Protein | Fat | Sodium | Potassium | Brand | Notes |
The index in the cell A2 use the Hash macro (it is implied the third Party Hash macro is installed):
=TEXTHASH(CONCATENATE(B2,L2,F2),"MD5")
The goal is to have a unique index and to do so the hash is calculated using the name of the food (B2), the value in carbs (F2) and the brand (L2).
The field in the table are mostly following the SQL table structure (see Monitoring health data - an improvement).
For extra info there are these fields:
- Serv X cont
Serving per container - the number of serving you can expect from the container or how many servings can be obtained from a recipe - Notes
Just extra notes about the food
After the table, there is the formula for the formatting of the SQL insert statement.
First of all, a cell (O1) contains the starting structure of the statement :
Insert into t_food_type values ( |
Then below, this formula is applied :
=IF(B2="","",(CONCATENATE($O$1,"""",A2,"""", ",", """", B2, """", ",", C2, ",", """", D2, """", ",", F2, ",", G2, ",", H2, ",", I2, ",", J2, ",", K2, ",", """", L2, """", ",", """", M2, """", ");")))
The meaning is :
- if the field "Name" exists (not blank) then
- create a string using the field O1, plus the other fields, starting from the field A2 (hash key) and ending with the field M2 (Notes)
- otherwise create a blank entry
The formula is then copied in all subsequent cells.
Here an example of the insert statement generation starting with the data on the table :
Insert into t_food_type values ("981a21f5a752cad048a834b9fd6cd258","Cooked Ham",4,"slices",1,60,8,2,580,0,"Land O'Frost","");
Insert into t_food_type values ("1a52451ea65def964ddb3c2be50811ce","Big Cup Noodles Homestyle Beef Flavor Ramen Noodle",1,"1/2 container",24,190,3,8,760,0,"Nissin","");
Insert into t_food_type values ("74ccbb6a8f0e507375ca5f727074a4e1","Texas Style Angus Beef Chili with Black Beans Soup",1,"cup",21,210,15,5,790,0,"Campbell","");
Insert into t_food_type values ("76d5f224ea4a78e3d737caa4eba0d1e","iesta Chicken Lime Tortilla Soup with White Meat Chicken",1,"cup",13,110,9,1.5,790,0,"Campbell","");
.............................................................
.............................................................
After the table is manually populated, we end up with a list of insert capable to fill up the T_FOOD_TYPE table.
Populate T_FOOD
The same mechanism used to populate the T_FOOD_TYPE table, is used to populate the T_FOOD table too.
Like before, a new spreadsheet that collect the information to be put in the database is created (still refer to the Monitoring health data - my way #2 article)
Let's examine the spreadsheet used to format the insert statement.
The spreadsheet has two tabs:
- Food type
- Food
The Food tab, is structured as the database, raw.
Here the table structure:
Index | Date Meal | Type Meal | FoodIndex | Food name | Servings | Calculated carbs | Calculated salt |
The Calculated carbs and Calculated Salt are populated using data from the previous table.
Calculated carbs is :
=VLOOKUP(D2,'Food type'.$A$2:$M$156, 6, 0)*F2
The meaning is to look in the all previous tab (Food type) of the spreadsheet for the FoodIndex key, retrieve the number of carbs per serving and multiply for the number of serving (field Servings on this tab).
Similarly for the Calculated salt :
=VLOOKUP(D2,'Food type'.$A$2:$M$156, 10, 0)*F2
The meaning is to look in the all previous tab (Food type) of the spreadsheet for the FoodIndex key, retrieve the number of mg of salt per serving and multiply for the number of serving (field Servings on this tab).
Just to have a quick idea about the amount of salt of the selected food.
This should allow to generate a unique key for the each record.
The cell A2 contains this formula :
=TEXTHASH(CONCATENATE(B2,C2,D2,E2),"MD5")
Again the purpose is to obtain a unique key for each entry, to do so it used the date of the meal (B2), the type of the meal (C2, e.g. Breakfast or Lunch or Dinner or Snack), the food index (D2, foreign key) and the food name (E2).
Note that the food name field is populated from the other Calc table (see above).
The cell A2 contains this formula :
=TEXTHASH(CONCATENATE(B2,C2,D2,E2),"MD5")
Again the purpose is to obtain a unique key for each entry, to do so it used the date of the meal (B2), the type of the meal (C2, e.g. Breakfast or Lunch or Dinner or Snack), the food index (D2, foreign key) and the food name (E2).
Note that the food name field is populated from the other Calc table (see above).
After the table, there is the formula for the formatting of the SQL insert statement.
First of all, a cell (I1) contains the starting structure of the statement :
Insert into t_food values ( |
Then below, this formula is applied :
=IF(B2="","",(CONCATENATE($H$1, """", A2, """", ", str_to_date('",(TEXT(B2,"mm/dd/yy")), "', ", """", "%m/%d/%Y", """", "), ", """",C2,"""",", ","""",D2,"""", ", " ,F2, ");")))
The meaning is :
- if the field "Date Meal" exists (not blank) then
- create a string using the field H1, plus the other fields, starting from the field A2 (hash key) and ending with the field F2 (Servings)
- otherwise create a blank entry
The formula is then copied in all subsequent cells.
Here an example of the insert statement generation starting with the data on the table :
Insert into t_food values (84280b208c8c61a7aab5c4be5fb25385, str_to_date('12/29/14', "%m/%d/%Y"), "Breakfast", "ac118ebecb401ae2e9fe42b8f7b1da8c", 2);
Insert into t_food values (16df74f3237c526a71186884b0cd7aa1, str_to_date('12/29/14', "%m/%d/%Y"), "Breakfast", "254a86d2153bfbc149f51d63c7113952", 1);
Insert into t_food values (532061254f4761e69bcf627c4916f3c2, str_to_date('12/29/14', "%m/%d/%Y"), "Lunch", "1b4f22d0d92b9185406cf6d815fd2c4c", 1);
Insert into t_food values (34c6041c3126488e599aa467e8a0d4de, str_to_date('12/29/14', "%m/%d/%Y"), "Lunch", "af3a803a27460603422bf47322ba6d4", 2);
Insert into t_food values (532061254f4761e69bcf627c4916f3c2, str_to_date('12/29/14', "%m/%d/%Y"), "Dinner", "1b4f22d0d92b9185406cf6d815fd2c4c", 2);
....................................................................
....................................................................
Basically after the table is manually populated, we end up with a list of insert capable to fill up the T_FOOD table.
Saturday, April 25, 2015
Monitoring health data - populating measurement tables
This article continue the discussion about the building of the system to collect my health numbers.
There are already many data stored in LibreOffice Calc tables and other LibreOffice documents.
Because of that when/where possible macro will be used to generate the mySQL commands to populate the tables.
Because of that when/where possible macro will be used to generate the mySQL commands to populate the tables.
The T_MES_TYPE table will be populated manually, but T_MES, T_FOOD_TYPE and T_FOOD can use some kind of automation mechanism to do so.
Populate T_MES_TYPE
Here a list of mySQL commands to populate the T_MES_TYPE table.
It is easy to populate the table, just open a mySQL session in a terminal, connect to the database and then cut & paste the lines below.
It is easy to populate the table, just open a mySQL session in a terminal, connect to the database and then cut & paste the lines below.
connect name_database;
insert into t_mes_type values (1, "Glicemy", "ml/dg");
insert into t_mes_type values (2, "Weight", "lb");
insert into t_mes_type values (3, "Carbs", "count");
insert into t_mes_type values (4, "Blood Systolic", "mmHg");
insert into t_mes_type values (5, "Blood Diastolic", "mmHg");
insert into t_mes_type values (6, "Heart beat", "bpm");
insert into t_mes_type values (1, "Glicemy", "ml/dg");
insert into t_mes_type values (2, "Weight", "lb");
insert into t_mes_type values (3, "Carbs", "count");
insert into t_mes_type values (4, "Blood Systolic", "mmHg");
insert into t_mes_type values (5, "Blood Diastolic", "mmHg");
insert into t_mes_type values (6, "Heart beat", "bpm");
insert into t_mes_type values (7, "Ketons", "count");
insert into t_mes_type values (8, "Exercise elliptical", "min");
insert into t_mes_type values (9, "Exercise walking", "miles");
insert into t_mes_type values (10, "Exercise hiking", "miles");
Populate T_MES table from Spreadsheet
Since already exists many data stored in the LibreOffice spreadsheet, here there is a procedure to populate the data stored in the tables.Populate T_MES - glucose level
- Open the spreadsheet
- Create a separate tab and rename it to give a meaning (i.e. Export SQL glucose)
- In the cell A1 copy this fixed string : Insert into t_mes values (
- In the cell J2 use the Hash macro (it is implied the third Party Hash macro is installed):
=TEXTHASH(CONCATENATE('All times'.A2,'All times'.F2,'All times'.G2),"MD5") - Copy in the other Jx fields the formula above
- In the cell A2 copy this formula :
=IF (OR('All times'.G2 = 0, 'All times'.G2 = ""), "",(CONCATENATE($A$1, """", J2,"""", ", str_to_date('", (TEXT('All times'.A2,"mm/dd/yy")), "',", """", "%m/%d/%Y", """", ")", ", str_to_date('", (TEXT('All times'.F2,"hh:mm:ss")), "',", """", "%H:%i:%s", """", ")", ", 1, ", 'All times'.G2, ");"))) - Copy all the result strings in the mysql
Insert into t_mes values ("31ba5af2e19e9c8e9bc35bbd1f588fb1", str_to_date('10/28/14',"%m/%d/%Y"), str_to_date('19:45:00',"%H:%i:%s"), 1, 150);
Invalid entries will be blanket
Populate T_MES - weight
- Open the spreadsheet
- Create a separate tab and rename it to give a meaning (i.e. Export SQL weight)
- In the cell A1 copy this fixed string : Insert into t_mes values (
- In the cell J2 use the Hash macro (it is implied the third Party Hash macro is installed):
=TEXTHASH(CONCATENATE('All times'.A2,'All times'.F2,'All times'.H2),"MD5") - Copy in the other Jx fields the formula above
- In the cell A2 copy this formula :
=IF ( OR ('All times'.H2 = 0, 'All times'.H2 = ""), "", (CONCATENATE($A$1, ,"""",J2,"""", ", str_to_date('", (TEXT('All times'.A2,"mm/dd/yy")), "',", """", "%m/%d/%Y", """", ")", ", str_to_date('", (TEXT("08:00:00","hh:mm:ss")), "',", """", "%H:%i:%s", """", ")", ", 2, ", 'All times'.H2, ");"))) - Copy the content of the cell A2 for the remains rows up tp the number of rows present in the tab All times (see the limit in the tab All times)
- Copy all the result strings in the mysql
Insert into t_mes values ("4af7c8660faee64b3e126c3c1717b510", str_to_date('10/28/14',"%m/%d/%Y"), str_to_date('08:00:00',"%H:%i:%s"), 2, 177.6);
Invalid entries will be blanketed
Populate T_MES - Ketons
- Open the spreadsheet
- Go in the tab of the month (to be repeated for each month)
- In the cell U1 copy this fixed string : Insert into t_mes values (
- In the cell T2 column create the index using the hash formula:
=TEXTHASH(CONCATENATE(A2,F2,K2),"MD5") - Copy in the other Tx fields the formula above
- In the cell U2 copy this formula :
=IF ( K2 = "", "", (CONCATENATE($U$1, """",T2,"""", ", str_to_date('", (TEXT(A2,"mm/dd/yy")), "',", """", "%m/%d/%Y", """", ")", ", str_to_date('", (TEXT("09:00:00","hh:mm:ss")), "',", """", "%H:%i:%s", """", ")", ", 7, ", K2, ");"))) - Copy the content of the cell U2 for the remains rows up tp the number of rows present in the monthly tab
- Copy all the result strings in the mysql
Here an example of a generated entry (invalid entries are blanketed).
Insert into t_mes values ("fe8565c8659775e73957e9c0485101f4", str_to_date('03/01/15',"%m/%d/%Y"), str_to_date('09:00:00',"%H:%i:%s"), 7, 0); |
Alternatively (I prefer this way) is possible to prepare ASCII files with the generated commands and feed mySQL with these files.
In this way, the files allows to recreate the database from the scratch if necessary, a form of backup, and also is easy to duplicate the database on different machines.
The files can be edited to add comments and explain the purpose of specific commands/fields.
Sunday, April 19, 2015
MSP430 - generating a PWM signal
This article discuss some basic ways to generate a PWM signal using a MSP430.
A PWM signal is a digital signal with fixed frequency but varying duty cycle.
If the duty cycle of the PWM signal is varied with time, and the PWM signal is filtered, the output of the filter will be an analog signal.
There are mostly 3 ways to generate a PWM signal using a MSP430 :
Theory of operations
A PWM signal is a digital signal with fixed frequency but varying duty cycle.
If the duty cycle of the PWM signal is varied with time, and the PWM signal is filtered, the output of the filter will be an analog signal.
There are mostly 3 ways to generate a PWM signal using a MSP430 :
- loop
- timer
- interrupt
Loop
The easiest way to generate a PWM signal is to create an infinite loop and inside the loop, set a I/O pin ON or OFF, using a counter to determine when to change the ON vs. OFF time, comparing it to a "dutycycle" value. Also in the loop must be present a delay to determine the frequency of the signal.
The pro is obvious, is really easy to generate a PWM signal in this way.
But there are big cons with this method.
Let see some of them:
Two MSP430 subsystems are involved in generating a PWM signal with the timer, the clock subsystem and the timer subsystem.
The output pin of the PWM signal, is directly connected to the timer.
Once programmed the timer, the generation of the PWM signal doesn't require any additional software.
In this way, a timer is still involved, but instead to generate the PWM signal, it generate interrupts.
Any time the interrupt is fired, a piece of software provide to change the state of an I/O pin depending some counter values compared with a threshold, generating in this way the PWM signal.
The frequency of the signal is determined by the timer setting and the precision is depending by the number of "steps" of the counter.
For example, if we want a 100 Hz signal, we need to set up an interrupt timing "at least" set to fire every 1/(100 Hz * 2) i.e. 0.005 seconds.
It means that every 0.005 seconds we have an interrupt and change the state of the output, obtaining a square wave of 100 Hz.
But we want to control the duty cycle, and so we need to have a smaller interrupt time.
Let say we want to divide our 100 Hz in 10 "steps", so we need to set the timer to fire every 1/(100 Hz/10) = 0.001 seconds or 1 ms.
Every ms we have an interrupt and then we decide if having the output ON or OFF.
Our period is so divided in 10 1 ms steps, i.e. 0.001 * 10 = 0.1 sec. that converted is 100 Hz.
But only 10 steps is not good, so better to split the time more, at least 50 or 100.
Of course we have some limits depending the input clock and how long the interrupt function requires to operate.
So we have to play with the clock in order to have the micro go faster and really optimize the interrupt function.
The interrupt function must be executed in a time much shorter than 1 ms, and we need to decide if the output is high or low depending a counter value in that timeframe.
Here a flow chart to better explain the basics.
On the left a flow of the main code.
It simply initialize the system and enter in an infinite loop. Eventually is possible to have code to perform settings/change of the parameters in the loop.
On the right the flow of the timer interrupt.
Every time the interrupt is fired, it uses a counter compared with a threshold to determine if turn the signal ON or OFF and then update the counter restarting the timer.
To measure exactly how long on average the function last, a debug signal is used.
The code turn this debug signal ON just after started the interrupt and OFF just before to exit.
With an oscilloscope is then possible to measure how long the signal remain ON. That more or less would be the time used by the interrupt function.
Here a couple of pictures from my oscilloscope during some tests.
The pro is obvious, is really easy to generate a PWM signal in this way.
But there are big cons with this method.
Let see some of them:
- all the resources of the processor are devoted to generate the signal
- is extremely difficult to calculate a specific timing
- any extra operation added in the loop go to alter the frequency of the generated signal
- if interrupts are used the result signal is extremely instable
So the loop is not really something to consider for real use.
Timer
The second way to generate a PWM signal is to use a timer.
The MSP430 timer is capable to generate a PWM signal, it means that is possible to program a MSP430 timer specifically for the purpose to generate a PWM signal.
Because the signal in the end is generated by a piece of hardware, the result is extremely stable and precise.
Pro:
- very stable PWM signal
- extremely precise timing is possible
Cons:
- the timer is devoted only to the PWM signal generation since the I/O pin is connected to it
- only 1 PWM signal per timer is available
- setting up the timer can be complicated
Interrupt
The third alternative is to soft-generate the PWM, like in the loop solution, but using a timer interrupt instead a deal loop.
A generic timer interrupt is generated and every time the interrupt is fired, a function handle one or more I/O pins to generate the PWM signal.
Pro:
- stable PWM signal
- precise timing (but less than the full timer solution)
- possibility to have more than one PWM signals
- possibility to use the timer resource for other purposes
- easy to calculate the time
Cons:
- limited timing range
PWM generated by a timer
The output pin of the PWM signal, is directly connected to the timer.
Once programmed the timer, the generation of the PWM signal doesn't require any additional software.
Clock
The timer needs to be "fed" with a clock and there are different choices, depending the time required and the precision needed.PWM using a generic time interrupt
In this way, a timer is still involved, but instead to generate the PWM signal, it generate interrupts.
Any time the interrupt is fired, a piece of software provide to change the state of an I/O pin depending some counter values compared with a threshold, generating in this way the PWM signal.
The frequency of the signal is determined by the timer setting and the precision is depending by the number of "steps" of the counter.
For example, if we want a 100 Hz signal, we need to set up an interrupt timing "at least" set to fire every 1/(100 Hz * 2) i.e. 0.005 seconds.
It means that every 0.005 seconds we have an interrupt and change the state of the output, obtaining a square wave of 100 Hz.
But we want to control the duty cycle, and so we need to have a smaller interrupt time.
Let say we want to divide our 100 Hz in 10 "steps", so we need to set the timer to fire every 1/(100 Hz/10) = 0.001 seconds or 1 ms.
Every ms we have an interrupt and then we decide if having the output ON or OFF.
Our period is so divided in 10 1 ms steps, i.e. 0.001 * 10 = 0.1 sec. that converted is 100 Hz.
But only 10 steps is not good, so better to split the time more, at least 50 or 100.
Of course we have some limits depending the input clock and how long the interrupt function requires to operate.
So we have to play with the clock in order to have the micro go faster and really optimize the interrupt function.
Here a flow chart to better explain the basics.
On the left a flow of the main code.
It simply initialize the system and enter in an infinite loop. Eventually is possible to have code to perform settings/change of the parameters in the loop.
On the right the flow of the timer interrupt.
Every time the interrupt is fired, it uses a counter compared with a threshold to determine if turn the signal ON or OFF and then update the counter restarting the timer.
To measure exactly how long on average the function last, a debug signal is used.
The code turn this debug signal ON just after started the interrupt and OFF just before to exit.
With an oscilloscope is then possible to measure how long the signal remain ON. That more or less would be the time used by the interrupt function.
Here a couple of pictures from my oscilloscope during some tests.
Debug signal in the timer interrupt - DCO set for 16 Mhz selection. The irregular wave indicates different execution timing, approx 3.5 us average execution time |
PWM signal generated, 10 steps, approx 10Khz frequency - DCO set for 16 Mhz selection |
Saturday, April 11, 2015
MSP430 - setting up the clock
All the microcontrollers needs a clock signal to work.
The MSP430 family is not an exception and actually there are many choices when we talk about the clock.
It is important ALWAYS to have handy the LATEST MSP430 family document and the specific chipset documentation, for example the MSP430F20x2 family (an entry level).
Some schematics/pictures shown here are copied from the MSP430 family document.
Let see the MSP430 clock system
The first thing that come up from the picture above, is that we have three different clock signal generated:
The most important signal generated is the MCLK, the Main System Clock.
As the name imply, this is the clock signal used by the core of the MSP430 chipset, the CPU and basic signals (memory bus/I/O bus/ecc.).
The SMCLK signal is the Sub system clock.
It is normally connected to the peripherals, like the Timer, Watchdog and every peripheral that can require a clock.
The ACLK is an Auxiliary clock.
Sometime it can be necessary to have peripherals using different clocks. For example a UART can require a special timing if compared with the other peripherals or a specific timer needs a low and precise timing.
The Auxiliary clock cannot use the DCO oscillator. It can use only the crystal oscillator.
When the chip is turned ON, i.e. after a hard reset, the clock subsystem is set to generate an approx. 800 kHz signal on the MCLK and SMCLK pin.
This allows the chipset to be able to start to execute instructions. A default clock mechanism must be present otherwise it would be impossible to "program the clock subsystem" if no instructions can be executed.
By default, the source for the SMCLK is the same of the MCLK, the DCO generator.
There are four possible sources for the clock:
This clock runs around 12 kHz and it can be used when the chipset is put in low power mode.
It is reasonably precise.
If the precision of the clock is not an issue, there is no need to worry about using calibrated values for the DCO.
Because the tolerance of the components, each MSP430 needs a different set of resistor values to set up the clock for specific frequencies.
It would be a very time consuming task to use external resistors, figuring out what is the correct value for a specific frequency, but fortunately TI though about that.
Every MSP430 chip has a table containing the calibrated (values) for the internal resistor array.
Is enough to read the table and acquire the value for the setting needed.
It is also possible to re-write the table for specific needs, as described in this article.
To determine what setting is needed for specific frequency, requires to study the specific chipset datasheet.
For example, for the MSP430f2012 the datasheet has a table indicating what frequency, with quite a tolerance, correspond to different settings of some specific registers.
Looking at the table, the frequencies generated by the DCO have a quite big tolerance.
This why it could be necessary to re-calibrate the DCO values if a more precise frequency is needed.
As the name imply, these circuits allows to generate a frequency dependent by a crystal.
They are less flexible than the DCO but they can be very precise and stable.
At least one crystal oscillator is present on every MSP430 chipset.
Here some examples about how is possible to set up the MSP430 clock.
The examples are using the MSP430F2012.
The default setting is for a middle/low frequency, around 800kHz (800kHz to 1.5 MHz), but the DCO can reach the 16 MHz in some chipsets.
Unless specific needs, is not a good idea to set the DCO for the maximum frequency.
Mainly because more fast the chip run, more current use and more heat is generated, but also because higher is the generated frequency, lower is the stability and precision.
Is a good idea to use a an external crystal if high speed and precision is required.
To determine what frequency to use it is mandatory to read the data sheet of the specific component, because each device has an internal table with some values to use for the DCO.
Said so, a typical DCO setting for about 8 Mhz is this one.
DCOCTL = 0x60;
BCSCTL1 = 0xB3;
BCSCTL2 = 0x00;
BCSCTL3 = 0x0C;
The DCOCTL (Digitally Controlled Oscillator Control register) after a reset is set for:
The BCSCTL1 register (Basic Clock Control Register 1) after the reset has the value of 84 hex (1000 0100), i.e. :
When is necessary to count time for a clock, timer or watch, normally it is used a crystal of 32768-Hz (3.2768 kHz) because is easy to divide this frequency to obtain 1 second.
Of course we don't want the main clock system signal be so slow, this is the typical setting for the ACLK signal.
Let see what we need to be aware and what to do to have the basic clock set on that.
First of all some hardware is required.
Then the software.
We need to set up some chipset registers in order to have the clock up and running.
BCSCTL1 |= DIVA_3; /* ACLK/8 */
BCSCTL3 |= XCAP_3; /* 12.5pF cap */
Let see some details.
The BCSCTL1 register (Basic Clock Control Register 1) after the reset has the value of 84 hex (1000 0100), i.e. :
The MSP430 family is not an exception and actually there are many choices when we talk about the clock.
It is important ALWAYS to have handy the LATEST MSP430 family document and the specific chipset documentation, for example the MSP430F20x2 family (an entry level).
Some schematics/pictures shown here are copied from the MSP430 family document.
Let see the MSP430 clock system
The first thing that come up from the picture above, is that we have three different clock signal generated:
- MCLK
- SMCLK
- ACLK
MCLK
The most important signal generated is the MCLK, the Main System Clock.
As the name imply, this is the clock signal used by the core of the MSP430 chipset, the CPU and basic signals (memory bus/I/O bus/ecc.).
SMCLK
The SMCLK signal is the Sub system clock.
It is normally connected to the peripherals, like the Timer, Watchdog and every peripheral that can require a clock.
ACLK
The ACLK is an Auxiliary clock.
Sometime it can be necessary to have peripherals using different clocks. For example a UART can require a special timing if compared with the other peripherals or a specific timer needs a low and precise timing.
The Auxiliary clock cannot use the DCO oscillator. It can use only the crystal oscillator.
Clock sources
When the chip is turned ON, i.e. after a hard reset, the clock subsystem is set to generate an approx. 800 kHz signal on the MCLK and SMCLK pin.
This allows the chipset to be able to start to execute instructions. A default clock mechanism must be present otherwise it would be impossible to "program the clock subsystem" if no instructions can be executed.
By default, the source for the SMCLK is the same of the MCLK, the DCO generator.
There are four possible sources for the clock:
- Very low frequency clock
- DCO
- Crystal oscillator 1
- Crystal oscillator 2
Some chipset could have only one crystal oscillator, so is important to know what chipset you are using.
Very low frequency clock
This clock runs around 12 kHz and it can be used when the chipset is put in low power mode.
It is reasonably precise.
DCO
The DCO (Digitally Controlled Oscillator) is the default source of clock for the MCLK and SMCLK.
As the name imply, it is possible to set up this oscillator simply writing the setting in some registers.
Different frequencies can be generated simply changing some register settings.
There are Pro and Cons using the DCO.
There are Pro and Cons using the DCO.
Pro:
- flexible frequency generator
- doesn't require ANY external hardware
- fast
Cons:
- less stable and precise than crystal
- it require a tuning procedure
DCO calibrated values
The DCO uses resistors, external or internal, to set up a specific frequency.If the precision of the clock is not an issue, there is no need to worry about using calibrated values for the DCO.
Because the tolerance of the components, each MSP430 needs a different set of resistor values to set up the clock for specific frequencies.
It would be a very time consuming task to use external resistors, figuring out what is the correct value for a specific frequency, but fortunately TI though about that.
Every MSP430 chip has a table containing the calibrated (values) for the internal resistor array.
Is enough to read the table and acquire the value for the setting needed.
It is also possible to re-write the table for specific needs, as described in this article.
To determine what setting is needed for specific frequency, requires to study the specific chipset datasheet.
For example, for the MSP430f2012 the datasheet has a table indicating what frequency, with quite a tolerance, correspond to different settings of some specific registers.
Looking at the table, the frequencies generated by the DCO have a quite big tolerance.
This why it could be necessary to re-calibrate the DCO values if a more precise frequency is needed.
Crystal Oscillators
As the name imply, these circuits allows to generate a frequency dependent by a crystal.
They are less flexible than the DCO but they can be very precise and stable.
At least one crystal oscillator is present on every MSP430 chipset.
Programming examples
Here some examples about how is possible to set up the MSP430 clock.
The examples are using the MSP430F2012.
Select DCO for ~8 MHz
After a reset, the main source for the clock, especially MCLK, is the DCO.The default setting is for a middle/low frequency, around 800kHz (800kHz to 1.5 MHz), but the DCO can reach the 16 MHz in some chipsets.
Unless specific needs, is not a good idea to set the DCO for the maximum frequency.
Mainly because more fast the chip run, more current use and more heat is generated, but also because higher is the generated frequency, lower is the stability and precision.
Is a good idea to use a an external crystal if high speed and precision is required.
To determine what frequency to use it is mandatory to read the data sheet of the specific component, because each device has an internal table with some values to use for the DCO.
Said so, a typical DCO setting for about 8 Mhz is this one.
DCOCTL = 0x60;
BCSCTL1 = 0xB3;
BCSCTL2 = 0x00;
BCSCTL3 = 0x0C;
- Frequency select middle range (value from 0 to 7, set to 3)
- Modulator section = 0
The setting to 0x60, according to the table above, set the frequency between 6 MHz to 9MHz.
The BCSCTL1 register (Basic Clock Control Register 1) after the reset has the value of 84 hex (1000 0100), i.e. :
- Crystal Oscillator 2 disabled (OFF)
- Crystal low frequency mode
- ACLK signal divided by 1 (i.e. no division)
- DCO Resistor select = 4 (nominal frequency for DCO)
After the selection (BCSCTL1 = 0xB3 - 1011 0011):
- Crystal Oscillator 2 disabled (OFF)
- Crystal low frequency mode
- ACLK signal divided by 8
- DCO Resistor select = 3
The BCSCTL2 after the reset is set to zero and no change is made, meaning:
- source for MCLK = DCO
- no divider for MCLK (divider = 1)
- source for SMCLK = DCO
- no divider for SMCLK (divider = 1)
- use internal resistor for frequency selection
The BCSCTL3 after the reset is set to zero:
- Crystal oscillator 2 range 0 to 4 MHz (not used anyway)
- 3.2768 kHz crystal selected (not used anyway)
- 6 pf capacitor selected for crystal (not used anyway)
After the writing (0x0C - 0000 0011)
- Crystal oscillator 2 range 0 to 4 MHz (not used anyway)
- 3.2768 kHz crystal selected (not used anyway)
- 1 pf capacitor selected for crystal (not used anyway)
Note that the first two bits are only reading.
Classic watch generator
When is necessary to count time for a clock, timer or watch, normally it is used a crystal of 32768-Hz (3.2768 kHz) because is easy to divide this frequency to obtain 1 second.
Of course we don't want the main clock system signal be so slow, this is the typical setting for the ACLK signal.
Let see what we need to be aware and what to do to have the basic clock set on that.
First of all some hardware is required.
- connect the crystal
A 32768-Hz crystal need to be connected to the chipset (pin XIN and XOUT)
Usually this require also some capacitors other the crystal, but the chipset has them inside - setting the pins
Because the crystal is physically connected to some chip pins, we need to program the I/O subsystem accordingly.
i.e. we need to program the pins connected to the crystal to be rerouted to the clock subsystem.
By default, i.e. after a reset, assuming we are using an MSP430F2012, the XIN and XOUT pins are enabled, i.e. by default these pins are used for the crystal oscillator 1.
So no specific programming on the I/O subsystem is necessary to use a crystal.
Then the software.
We need to set up some chipset registers in order to have the clock up and running.
BCSCTL1 |= DIVA_3; /* ACLK/8 */
BCSCTL3 |= XCAP_3; /* 12.5pF cap */
Let see some details.
The BCSCTL1 register (Basic Clock Control Register 1) after the reset has the value of 84 hex (1000 0100), i.e. :
- Crystal Oscillator 2 disabled (OFF)
- Crystal low frequency mode
- ACLK signal divided by 1 (i.e. no division)
- Resistor select = 4 (nominal frequency for DCO)
So the register controls different parts of the clock subsystem.
The line BCSCTL1 |= DIVA_3; set only the DIVA bits, changing the original value from 0 to 3, setting the divisor of the ACLK signal to 8. i.e. the generated frequency of the ACLK will be divided by 8.
The BCSCTL3 register after the reset has the value of 00x (the first two bits are to indicate some fault condition so they can have random setting after a reset).
i.e.:
- Range for Crystal oscillator 2 : 0 to 1 MHz crystal
- 3.2768 kHz crystal on oscillator 1
- 1 pf internal capacitor
The bit 2 and 3 select an internal capacitor to be used with an external crystal.
In our example, we use a 12.5 pF internal capacitor so the selection is 3 (11) for these bits, forced with the line : BCSCTL3 |= XCAP_3;
This is enough to have the ACLK signal generated.
The ACLK signal will have a 32768 Hz / 8 = 4096 Hz.
The ACLK signal will have a 32768 Hz / 8 = 4096 Hz.
This value is easily used by the timer in order to generate precise and low periods.
Sunday, April 5, 2015
Monitoring health data - an improvement
The purpose of the article is to start a discussion about a "system" capable to store and retrieve/analyze health data.
More articles will follow on specific issues. This article is the continuation of the previous articles "Monitoring health data - my way #1 and #2".
The use of the spreadsheet as main tool to collect data for now is preserved, because it is easy to store the information in that way, but retrieve them in a meaningful way can become tricky.
This why I started to think a better way to do this "daily chore", in a way that will easily allow me to create better reports and analyze the data more deeply, creating also reports "on the fly".
The system is based on a database that collect all the information and a set of macro/applications/programs to facilitate the data entry and the retrieval.
The database is based on mySQL.
Macro in the spreadhseet (Libreoffice Calc) allows to export the data stored in the SQL tables.
The database is based on some tables that collects the measurements and other related values.
At the moment I created 4 tables:
These are the main tables used to store the health measurements.
The main table (T_MES) contains the actual readings, and the T_MES_TYPE contains specific information about the type of measurement.
Each measure is stamped with date and time, however some measurements will have a fake time.
For example the weight. Usually there is an entry per day, so the time is forced at 8:00 am regardless when actually was taken, because not always I can measure at the same time.
Let see in details the fields of T_MES:
Here the mySQL commands to create the two tables :
More articles will follow on specific issues. This article is the continuation of the previous articles "Monitoring health data - my way #1 and #2".
The use of the spreadsheet as main tool to collect data for now is preserved, because it is easy to store the information in that way, but retrieve them in a meaningful way can become tricky.
This why I started to think a better way to do this "daily chore", in a way that will easily allow me to create better reports and analyze the data more deeply, creating also reports "on the fly".
The system
The system is based on a database that collect all the information and a set of macro/applications/programs to facilitate the data entry and the retrieval.
The database is based on mySQL.
Macro in the spreadhseet (Libreoffice Calc) allows to export the data stored in the SQL tables.
The database
The database is based on some tables that collects the measurements and other related values.
At the moment I created 4 tables:
- Measurement table
- Measurement type table
- Food table
- Food type table
Measurement tables
T_MES
These are the main tables used to store the health measurements.
The main table (T_MES) contains the actual readings, and the T_MES_TYPE contains specific information about the type of measurement.
Each measure is stamped with date and time, however some measurements will have a fake time.
For example the weight. Usually there is an entry per day, so the time is forced at 8:00 am regardless when actually was taken, because not always I can measure at the same time.
Let see in details the fields of T_MES:
- mesIndex
Unique ID for the record, it is a MD5 Hash of the date, time and value measured - dateMeasure
It is the date of the measurement - timeMeasure
It is the time of the measurement. Weight and Ketons have a fake time entry. 8:00 am for Weight, 9:00 am for Ketons - typeMeasure
Foreign key for the table T_MES_TYPE - noteMeasure
Contains specific measurement note. The nature of the note depends about the measurement. - valueMeasure
Value of the measurement
The T_MES_TYPE table contains information about the measure.
- typeMeasure
Unique ID for the record. Incremental number - description
A brief description of the measurement. Explains what is measured - units
Measurement unit of the measurement
Here the data to load in the T_MES_TYPE table :
typeMeasure code | units | description |
1 | ml/dg | Glycemy |
2 | lb | Weight |
3 | count | Carbs |
4 | mmHg | Blood pressure systolic |
5 | mmHg | Blood pressure diastolic |
6 | bpm | Heart beat (beat per minute) |
7 | count |
Ketons
|
8 | minutes |
Exercise elliptical
|
9 | miles |
Exercise walking
|
10 | miles |
Exercise hiking
|
Here the mySQL commands to create the two tables :
create table if not exists t_mes (mesIndex varchar(40) not null primary key, dateMeasure date, timeMeasure time, typeMeasure numeric, valueMeasure numeric);
create table if not exists t_mes_type (typeMeasure numeric not null primary key, description varchar(20), unit varchar(10));
T_FOOD
The T_FOOD tables (T_FOOD and T_FOOD_TYPE) stores information about the food eaten.
Let see in details the fields of T_FOOD:
- foodIndex
Unique ID for the record, it is a MD5 Hash of the date, time and value measured - dateMeal
It is the date of the meal - typeMeal
It is the time of the meal according to a fixed schedule.
It is a fixed value like this : - Breakfast
- Lunch
- Dinner
- Snack
- foodType
Foreign key for the table T_FOOD_TYPE - serving
Number of serving consumed
The T_FOOD_TYPE table contains information about the food.
- foodType
Unique ID for the record. Hash of the food name, brand and carbs - name
Name of the food - servings
Number of servings in a product (if applicable) - servingUnits
Measurement unit used for the servings - carbs
Net Carbs in grams contained in 1 serving - calories
Calories contained in 1 serving - protein
Proteins in grams contained in 1 serving - totalFat
Total fat in grams contained in 1 serving - sodium
Salt in milligrams contained in 1 serving - potassium
Potassium in milligrams contained in 1 serving - brand
Name/description brand of the food. For vegetables/fruit use the word "raw". - notes
Notes about the food
Here the mySQL commands to create the two tables :
create table if not exists t_food (foodIndex varchar(40) not null primary key, dateMeal Date, typeMeal varchar(30), foodType varchar(40), serving Numeric);
create table if not exists t_food_type( foodType varchar(40) primary key not null, name varchar(40), servings Float, servingUnits varchar(15), carbs Float, calories Float, protein Float, totalFat Float, sodium Float, potassium Float, brand varchar(40), notes varchar(40));
Sunday, March 29, 2015
Monitoring health data - my way - #2
On this article I'll discuss how I track data related to the food.
A very important thing to do if you are dieting or keeping track of your health numbers, is to monitor the carbs and other nutrient intake, i.e. how many carbs you are eating.
In order to do so, it is important to know exactly what and when you are eating.
It seems easy but is not.
Why is not easy ? Well, let see some reasons (just a few) :
Here an example of entry:
Again, the main purpose of this document is to have a quick recap of the food I usually ate, in order to avoid to do the same research over and over.
On this document are also documented some "home made recipes", in order to calculate the nutrition info for that.
What I usually do, is to put down the basic nutrients of each component of the recipe, then calculate the total amount of carbs (and other nutrients) and then divide in cups or bowls.
Once you figure out how many carbs (and other nutrients) are in the food, the second step is to write down somewhere what you ate on a specific day.
This is the Food Journal document.
For each day there are 4 entries :
More details are put in this document, more is easy to calculate the carbs but there is always a trade between efficiency and time spent doing that.
Being too precise requires a lot of time, so know what to write as amount of information is something that is coming with the experience of doing that daily.
Note that the food journal reports mainly the carbs intake and not all the others nutrient,
This because the carbs intake is the main key in my case, however, other articles will explain how to use the nutrient information and create a daily journal.
In the end the goal is to come up with some carbs number to put in the spreadsheet I described in the previous article (Monitoring health data - my way #1).
The day is divided in 6 time areas :
A very important thing to do if you are dieting or keeping track of your health numbers, is to monitor the carbs and other nutrient intake, i.e. how many carbs you are eating.
In order to do so, it is important to know exactly what and when you are eating.
It seems easy but is not.
Why is not easy ? Well, let see some reasons (just a few) :
- not all the food you are eating is labeled
- the food is not "homogeneous", the same food can be present in different forms
- often a processed food have different characteristics than a less processed food
- often are indicated base chemical compost rather than more "human" description
- different companies label the food in different way
- all the companies who sell food, always try to hide or manipulate information in order to make more palatable the food they sell. The rule seems to be, if you can't be vague, obscure with chemistry and strange words
- hidden basic ingredients in processed food (like salt or sugar) often requires to "split" a food in it's basic elements
- etc.
So monitoring what you want to eat is not an easy business, it takes time and organization.
Here is "my way". Repeating myself, this is how I do that, I'm not stating it is the right way to do it.
It is good for me.
I maintain basically 3 documents :
- a "food information" document (word processor)
- a "food journal" document (word processor)
- the spreadsheet where I track also the sugar level and other measurements (spreadsheet)
Food information
The food information document contains information about the food I eat.
Usually I save a picture of the food or box, for an easy visual reference, and then some nutrient information.
Plus I add some notes to clarify how many carbs are actually present, just to simplify when I have to figure out quickly how much carbs I'm having.
The main problem is due by the fact that manufacturers give the information often in a very complicated way.
Plus I add some notes to clarify how many carbs are actually present, just to simplify when I have to figure out quickly how much carbs I'm having.
The main problem is due by the fact that manufacturers give the information often in a very complicated way.
For example, many "soups" containers contains 2 servings, but often the nutrient information are for about 1 serving.
Often you find 2.5 servings per container, other times 1 ... doesn't exists a standard.
Some manufactures express the "serving" in grams, other in oz, other per cup, other per bowl other as a generic "serving", or specific food description.
Often you find 2.5 servings per container, other times 1 ... doesn't exists a standard.
Some manufactures express the "serving" in grams, other in oz, other per cup, other per bowl other as a generic "serving", or specific food description.
So in order to figure out what you are eating, to calculate carbs and other measurement, you need to spend time researching information.
Thus I decided to "save" these researches, the results, in a document.
Each entry has a picture of the product, a copy of the nutrition chart, a thumb up or down to indicate that tastes good, and eventually some notes.
Each entry has a picture of the product, a copy of the nutrition chart, a thumb up or down to indicate that tastes good, and eventually some notes.
Here an example of entry:
Again, the main purpose of this document is to have a quick recap of the food I usually ate, in order to avoid to do the same research over and over.
On this document are also documented some "home made recipes", in order to calculate the nutrition info for that.
What I usually do, is to put down the basic nutrients of each component of the recipe, then calculate the total amount of carbs (and other nutrients) and then divide in cups or bowls.
Food journal
Once you figure out how many carbs (and other nutrients) are in the food, the second step is to write down somewhere what you ate on a specific day.
This is the Food Journal document.
For each day there are 4 entries :
- Breakfast
- Lunch
- Dinner
- Snacks
Each entry will collect information about what I'm eating. Quantity, food, estimated carbs, often divided by food.
With these info I can sum up the number of carbs for each "period" and transpose that value in the spreadsheet.
With these info I can sum up the number of carbs for each "period" and transpose that value in the spreadsheet.
Here an example of entry :
February 26, 2015
-
Breakfast
1 low carb tortilla (3g) with cheese, 4 slices capocollo (0g), eggs beaterCoffee -
Lunch
1 serving Chicken Enchilada bake (15g)
Pringles chip onion sour – single serve (10g)
Cornetti single serving (3 g) -
Dinner
Panera Bread – Chicken Kale and sweet potato soup – 1 cup (9g)
1 Morey's grilled salmon (1g) with zucchini (5g) -
Snacks10 am – 1 pouch Skinny zero popcorn (5g)3 pm - Chiquita – Bites juicy red apple (6g) with string cheese
9 pm – low carb cake (4 g)
Being too precise requires a lot of time, so know what to write as amount of information is something that is coming with the experience of doing that daily.
Note that the food journal reports mainly the carbs intake and not all the others nutrient,
This because the carbs intake is the main key in my case, however, other articles will explain how to use the nutrient information and create a daily journal.
Spreadsheet
In the end the goal is to come up with some carbs number to put in the spreadsheet I described in the previous article (Monitoring health data - my way #1).
The day is divided in 6 time areas :
- breakfast
- morning snack
- lunch
- afternoon snack
- dinner
- night snack
For each area the goal is to assign a value (if any).
See the previous document for details.
See the previous document for details.
Subscribe to:
Posts (Atom)