How do you correctly debug A/D convertor code in MPLAB X v5.05 simulator - microcontroller

This is a continuation of the question posed in How do you run a SCL file in MPLAB without a "Run SCL" button
I have an assembly code for PIC18F458 that gets data from channel 0 (RA0) of ADC and displays the result on PORTC and PORTD.
Although, I have managed to verify that the code operates as desired within Proteus, I am struggling to do the same within the MPLAB X simulator environment using a SCL file, and I suspect that this is due to the way that the text files, referred to by it, are laid out. (Please see below)
testbench for "pic18f458" is
begin
process is
file datafile : text;
variable intVar : integer;
variable sampling_voltage : integer;
variable fileStatus : file_open_status;
variable fileLine : line;
begin
loop
report("Analog injection started...");
file_open(fileStatus, datafile, "text2.txt", read_mode);
if fileStatus == open_ok then
report("Reading the values file...");
while endfile(datafile) == false loop
wait until ADCON0.GO_nDONE == '1';
report("Conversion started");
readline(datafile, fileLine);
wait for 400 ns;
read(fileLine, intVar);
sampling_voltage := intVar; -- sample input voltage
wait until ADCON0.GO_nDONE == '0';
report("Conversion ended");
if ADCON1.ADFM == '0' then -- left justified
ADRESH <= sampling_voltage / 4;
ADRESL <= sampling_voltage * 64;
else -- right justified
ADRESH <= sampling_voltage / 256;
ADRESL <= sampling_voltage;
end if;
end loop;
file_close(datafile);
end if;
end loop;
wait;
end process;
end testbench;
The SCL file refers to 1 of 2 text files during my debugging session (text.txt and text2.txt) laid out differently. The first consists of decimal numbers from 0 to 255 and the second consists of decimal numbers representing voltages in mV.
txt.txt
128
192
238
255
238
192
128
64
17
0
17
64
128
text2.txt
250 mV
500 mV
750 mV
1000 mV
1250 mV
1500 mV
1750 mv
2000 mV
2250 mv
2500 mv
2750 mv
3000 mv
3250 mV
3500 mV
3750 mV
4000 mV
4250 mV
4500 mV
4750 mv
5000 mV
In both cases, the ADC seems to just be churning out the numbers that it is receiving, instead of converting them. (Please see images below)
This is obviously no good, as I am getting values within the ADRES register that are greater than 10-bits, in particularly, with regards to my text2.txt values.
ADC Results with text.txt
ADC Results with text2.txt
Therefore, my question is how do I correctly debug my A/D convertor code in MPLAB X v5.05 simulator using a SCL file or any other methods?

Related

Lua: recursive function builts wrong table - pil4

while working on the exercise 2.2 of "programming in Lua 4" I do have to create a function to built all permutations of the numbers 1-8. I decided to use Heaps algorithm und made the following script. I´m testing with numbers 1-3.
In the function I store the permutations as tables {1,2,3} {2,1,3} and so on into local "a" and add them to global "perm". But something runs wrong and at the end of the recursions I get the same permutation on all slots. I can´t figure it out. Please help.
function generateperm (k,a)
if k == 1 then
perm[#perm + 1] = a -- adds recent permutation to table
io.write(table.unpack(a)) -- debug print. it shows last added one
io.write("\n") -- so I can see the algorithm works fine
else
for i=1,k do
generateperm(k-1,a)
if k % 2 == 0 then -- builts a permutation
a[i],a[k] = a[k],a[i]
else
a[1],a[k] = a[k],a[1]
end
end
end
end
--
perm = {}
generateperm(3,{1,2,3}) -- start
--
for k,v in ipairs (perm) do -- prints all stored permutations
for k,v in ipairs(perm[k]) do -- but it´s 6 times {1,2,3}
io.write(v)
end
io.write("\n")
end
debug print:
123
213
312
132
231
321
123
123
123
123
123
123

Extracting record from big endian data

I have the following code for network protocol implementation. As the protocol is big endian, I wanted to use the Bit_Order attribute and High_Order_First value but it seems I made a mistake.
With Ada.Unchecked_Conversion;
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
procedure Bit_Extraction is
type Byte is range 0 .. (2**8)-1 with Size => 8;
type Command is (Read_Coils,
Read_Discrete_Inputs
) with Size => 7;
for Command use (Read_Coils => 1,
Read_Discrete_Inputs => 4);
type has_exception is new Boolean with Size => 1;
type Frame is record
Function_Code : Command;
Is_Exception : has_exception := False;
end record
with Pack => True,
Size => 8;
for Frame use
record
Function_Code at 0 range 0 .. 6;
Is_Exception at 0 range 7 .. 7;
end record;
for Frame'Bit_Order use High_Order_First;
for Frame'Scalar_Storage_Order use High_Order_First;
function To_Frame is new Ada.Unchecked_Conversion (Byte, Frame);
my_frame : Frame;
begin
my_frame := To_Frame (Byte'(16#32#)); -- Big endian version of 16#4#
Put_Line (Command'Image (my_frame.Function_Code)
& " "
& has_exception'Image (my_frame.Is_Exception));
end Bit_Extraction;
Compilation is ok but the result is
raised CONSTRAINT_ERROR : bit_extraction.adb:39 invalid data
What did I forget or misunderstand ?
UPDATE
The real record in fact is
type Frame is record
Transaction_Id : Transaction_Identifier;
Protocol_Id : Word := 0;
Frame_Length : Length;
Unit_Id : Unit_Identifier;
Function_Code : Command;
Is_Exception : Boolean := False;
end record with Size => 8 * 8, Pack => True;
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Function_Code at 7 range 0 .. 6;
Is_Exception at 7 range 7 .. 7;
end record;
Where Transaction_Identifier, Word and Length are 16-bit wide.
These ones are displayed correctly if I remove the Is_Exception field and extend Function_Code to 8 bits.
The dump of the frame to decode is as following:
00000000 00 01 00 00 00 09 11 03 06 02 2b 00 64 00 7f
So my only problem is really to extract the 8th bit of the last byte.
So,
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Function_Code at 7 range 0 .. 6;
Is_Exception at 7 range 7 .. 7;
end record;
It seems you want Is_Exception to be the the LSB of the last byte?
With for Frame'Bit_Order use System.High_Order_First; the LSB will be bit 7,
(also, 16#32# will never be -- Big endian version of 16#4#, the bit pattern just doesn't match)
It may be more intuitive and clear to specify all of your fields relative to the word they're in, rather than the byte:
Unit_ID at 6 range 0..7;
Function_Code at 6 range 8 .. 14;
Is_Exception at 6 range 15 .. 15;
Given the definition of Command above, the legal values for the last byte will then be:
2 -> READ_COILS FALSE
3 -> READ_COILS TRUE
8 -> READ_DISCRETE_INPUTS FALSE
9 -> READ_DISCRETE_INPUTS TRUE
BTW,
by applying your update to your original program, and adding/changing the following, you program works for me
add
with Interfaces;
add
type Byte_Array is array(1..8) of Byte with Pack;
change, since we don't know the definition
Transaction_ID : Interfaces.Unsigned_16;
Protocol_ID : Interfaces.Unsigned_16;
Frame_Length : Interfaces.Unsigned_16;
Unit_ID : Interfaces.Unsigned_8;
change
function To_Frame is new Ada.Unchecked_Conversion (Byte_Array, Frame);
change
my_frame := To_Frame (Byte_Array'(00, 01, 00, 00, 00, 09, 16#11#, 16#9#));
I finally found what was wrong.
In fact, the Modbus Ethernet Frame definition mentioned that, in case of exception, the returned code should be the function code plus 128 (0x80) (see explanation on Wikipedia). That's the reason why I wanted to represent it through a Boolean value but my representation clauses were wrong.
The correct clauses are these ones :
for Frame use
record
Transaction_Id at 0 range 0 .. 15;
Protocol_Id at 2 range 0 .. 15;
Frame_Length at 4 range 0 .. 15;
Unit_id at 6 range 0 .. 7;
Is_Exception at 6 range 8 .. 8;
Function_Code at 6 range 9 .. 15;
end record;
This way, the Modbus network protocol is correctly modelled (or not but at least, my code is working).
I really thank egilhh and simonwright for making me find what was wrong and explain the semantics behind the aspects.
Obviously, I don't know who reward :)
Your original record declaration works fine (GNAT complains about the Pack, warning: pragma Pack has no effect, no unplaced components). The problem is with working out the little-endian Byte.
---------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | BE bit numbers
---------------------------------
| c c c c c c c | e |
---------------------------------
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | LE bit numbers
---------------------------------
so if you want the Command to be Read_Discrete_Inputs, the Byte needs to have BE bit 4 (LE bit 3) set i.e. LE 16#8#.
Take a look at this AdaCore post on bit order and byte order to see how they handle it. After reading that, you will probably find that the bit order of your frame value is really 16#08#, which probably is not what you are expecting.
Big Endian / Little Endian typically refers to Byte order rather than bit order, so when you see that Network protocols are Big Endian, they mean Byte order. Avoid setting Bit_Order for your records. In modern systems, you will almost never need that.
Your record is only one byte in size, so byte order won't matter for it by itself. Byte order comes into play when you have larger field values (>8 bits long).
The bit_order pragma doesn't reverse the order that the bits appear in memory. It simply defines whether the most significant bit (left most) will be logically referred to as zero (High_Order_First) or the least significant bit will be referred to as zero (Low_Order_First) when interpreting the First_Bit and Last_Bit offsets from the byte position in the representation clause. Keep in mind that these offsets are taken from the MSB or LSB of the scalar the record component belongs to AS A VALUE. So in order for the byte positions to carry the same meaning on a little endian CPU as they do on a big endian CPU (as well as the in memory representation of multibyte machine scalars, which exist when one or more record components with the same byte position have a last_bit value which exceeds the capacity of a single byte) then 'Scalar_Storage_Order must also be specified.

Cannot modify specific variable values over a specific dimension in netcdf

I have a netcdf file containing 4-D variables:
variables:
double maxvegetfrac(time_counter, veget, lat, lon) ;
maxvegetfrac:_FillValue = 1.00000002004088e+20 ;
maxvegetfrac:history = "From Topo.115MaCTRL_WAM_360_180" ;
maxvegetfrac:long_name = "Vegetation types" ;
maxvegetfrac:missing_value = 1.e+20f ;
maxvegetfrac:name = "maxvegetfrac" ;
maxvegetfrac:units = "-" ;
double mask_veget(time_counter, veget, lat, lon) ;
mask_veget:missing_value = -1.e+34 ;
mask_veget:_FillValue = -1.e+34 ;
mask_veget:long_name = "IF MYVEG4 EQ 10 AND I GE 610 AND J GT 286 THEN 16 ELSE MYVEG4" ;
mask_veget:history = "From desert_115Ma_3" ;
I'd like to use the variable "mask_veget" as a mask to alter values of the variable "maxvegetfrac" over specific regions, and over chosen values of its "veget" dimension.
To do so I am using ncap2. For example, if I want to set maxvegetfrac values over the 5th rank of veget dimension to 500 where mask_veget equals 6, I do :
> ncap2 -s "where (mask_veget(:,:,:,:)== 6) maxvegetfrac(:,5,:,:) = 500" test.nc
My problem is that in the resulting test.nc file, maxvegetfrac has been modified at the first rank of "veget" dimension, not the 5th one. And I get the same result if I run the script over the entire veget dimension:
ncap2 -s "where (mask_veget(:,:,:,:)== 6) maxvegetfrac(:,:,:,:) = 500" test.nc
So I am mistaking somewhere, but... where ?
Any help appreciated !
A couple of things you may not be aware of
you shouldn't be hyperslabbing a variable in the where body -it makes no sense at the moment.
It is ok to hyperslab in the where statement proving its a single index
as a dim with a single value collapses
Try this:
/*** hyper.nco *****/
maxvegetfrac5=maxvegetfrac(:,5,:,:);
where( mask_veget(:,5,:,:)== 6 )
maxvegetfrac5=500.0;
/* put the hyperslab back in */
maxvegetfrac(:,5,:,:)=maxvegetfrac5;
/* script end *****/
run the script now with the command
ncap2 -v -O -S hyper.nco test.nc out.nc
...Henry

SAS - hash tables and has_next

I'm looking for an elegant solution to the below issue that will help avoid code duplication. You can see that this line:
put auction_id= potential_buyer= ;* THIS GETS REPEATED;
Gets repeated in this code:
data results;
attrib potential_buyer length=$1;
set auction;
if _n_ eq 1 then do;
declare hash ht1(dataset:'buyers', multidata: 'y');
ht1.definekey('auction_id');
ht1.definedata('potential_buyer');
ht1.definedone();
call missing (potential_buyer);
end;
**
** LOOP THROUGH EACH POTENTIAL BUYER AND PROCESS THEM
*;
if ht1.find() eq 0 then do;
put auction_id= potential_buyer= ;* THIS GETS REPEATED;
ht1.has_next(result: ht1_has_more);
do while(ht1_has_more);
rc = ht1.find_next();
put auction_id= potential_buyer= ;* THIS GETS REPEATED;
ht1.has_next(result: ht1_has_more);
end;
end;
run;
I've simplified the above example to a single line as the real code block is quite long and complex. I'd like to avoid using a %macro snippet or a %include if possible as I'd like to keep the logic "within" the data step.
Here's some sample data:
data auction;
input auction_id;
datalines;
111
222
333
;
run;
data buyers;
input auction_id potential_buyer $;
datalines;
111 a
111 c
222 a
222 b
222 c
333 d
;
run;
I figured it out. Turned out to be pretty simple in the end just had a little trouble wrapping my brain around it:
data results;
attrib potential_buyer length=$1;
set auction;
if _n_ eq 1 then do;
declare hash ht1(dataset:'buyers', multidata: 'y');
ht1.definekey('auction_id');
ht1.definedata('potential_buyer');
ht1.definedone();
call missing (potential_buyer);
end;
**
** LOOP THROUGH EACH POTENTIAL BUYER AND PROCESS THEM
*;
if ht1.find() eq 0 then do;
keep_processing = 1;
do while(keep_processing);
put auction_id= potential_buyer= ;* THIS GETS DOESNT GET REPEATED ANYMORE =);
ht1.has_next(result: keep_processing);
rc = ht1.find_next();
end;
end;
run;
You can solve it this way....but Rob's answer is better.
data results;
%Macro NoDuplicate;
Put auction_id= potential_buyer= ; * No Longer Duplicated;
%Mend noduplicate;
attrib potential_buyer length=$1;
set auction;
if _n_ eq 1 then do;
declare hash ht1(dataset:'buyers', multidata: 'y');
ht1.definekey('auction_id');
ht1.definedata('potential_buyer');
ht1.definedone();
call missing (potential_buyer);
end;
**
** LOOP THROUGH EACH POTENTIAL BUYER AND PROCESS THEM
*;
if ht1.find() eq 0 then do;
%NoDuplicate
ht1.has_next(result: ht1_has_more);
do while(ht1_has_more);
rc = ht1.find_next();
%NoDuplicate
ht1.has_next(result: ht1_has_more);
end;
end;
run;

Windows Batch File Math Weirdness

Why doesn't this work?
#echo off
for /l %%i in (0, 1, 100) do (
for /l %%j in (0, 1, 10) do (
set /a curr=%%i*10 + %%j
echo %curr%
)
echo "-----------------------------"
)
This is the output I get from this:
1010
1010
1010
1010
1010
1010
1010
1010
1010
1010
1010
"----------------------------"
1010
1010
1010
1010
1010
1010
1010
1010
...
It seems like it precomputes the math before executing, so that when it does finally execute, %curr% is already at 1010. How do I keep it from doing that? I'm trying to get output like this:
0
1
2
3
4
5
6
7
8
9
10
"----------------------------"
11
12
...
Thanks in advance
Answer from Johannes Rössel (for those who might look for it later):
#echo off
setlocal enabledelayedexpansion enableextensions
for /l %%i in (0, 1, 100) do (
for /l %%j in (0, 1, 10) do (
set /a curr=%%i*10+%%j
echo !curr!
)
echo "-----------------------------"
)
Use delayed expansion by putting the following line before your loops:
setlocal enabledelayedexpansion enableextensions
And then use the environment variable as !curr! instead of %curr%.
You're changing the contents of an environment variable within a block and use the changed content again in the same block. This can't work without delayed expansion. The reason is that cmd expands variables like %foo% while parsing a command – and a command like if or for includes the block that may follow as well. Delayed expansion causes variables to be evaluated right before executing a command which is what you want here.
help set includes a description of what goes wrong without delayed expansion and works with it.

Resources