ADC Sampling Breakthrough - Page 51 — Parallax Forums

• Posts: 662
That and how do you print the characters. I assume that you are printing decimal not a plain ascii character. For example, I am printing the gps rmc string. I can print solely in ascii, but if I want to manipulate the numbers I have to convert to decimal. Then print in decimal. so if I was simply doing two plus two in decimal how do I print that in the p2asm that I am working with.
Thanks
• Posts: 11,635
edited 2019-11-27 22:31
Ah, no I don't have any decimal maths, all my maths is with binary integers. The BCD is stored temporarily because print order is big-endian but convert order is little. And the BCD printing loop tacks on the ASCII offset as it is printed. Printing is ASCII because that's what the terminal is.

• Posts: 662
@evanh
@ersmith 'evanh has been helping me but would you be able to assist also. I am thanks to evanh able to do some basic printing but it appears only ascii or strings
trying to print decimal numbers so I can do math. Any ideas? Thanks

Happy Thanksgiving where ever you are.
I have been attempting to just print the results of 2+2.
That is where I am starting.

'THIS WORKS****************************
add pa,#"8" 'THIS IS ASCII RIGHT?
mov number,pa
call #putchar

call #putnl

waitx ##sys_clk '* 15

'***********************************

'THIS DOES NOT WORK attempting to print decimals??

call #putchar
call #send_char

call #putchar
call #send_char

2+2.PNG 17.2K
• Posts: 5,022
send_char always sends an ASCII character. If you want to print a number as decimal, you'll have to convert it to ASCII (as a decimal number) first. That's what Evan was discussing earlier with his BCD section. He converts each digit one at a time by dividing by 10 and saving the remainder, and then prints the resulting string (by sending each digit out once). I don't have his code in front of me, but presumably he adds each digit to the ASCII value for "0" (namely 48). That is, to print a number between 0 and 99 you'd do something like:
```' WARNING: this is untested code, it probably does not work as-is
' it's just an example of the kind of thing you would have to do
' to print a small number as a decimal
qdiv  number, #10  ' divide number by 10
getqy digit2       ' get remainder
getqx digit1       ' get number/10; we assume it is < 10, if not we would have to iterate
add   digit1, #"0" ' convert digit1 to ASCII
mov   pa, digit1   ' print first digit
call  #send_char
mov   pa, digit2   ' print second digit
call  #send_char
```
Evan may already have a simpler routine for doing this kind of thing.

The key here is that you can easily convert a number between 0 and 9 (inclusive) to ASCII by just adding 48 (the ASCII value for "0"). But for numbers bigger than 9 this does not work; an ASCII character is just one character, whereas the string we would want to print for the number 10 consists of two characters, "1" and "0". So you have to break larger numbers up into smaller ones (the individual digits).
• Posts: 11,635
edited 2019-11-28 23:17
Oh, yeah, once you have your single digit, a value from 0-9, then it's just: ADD digit, #"0"
• Posts: 662
@ersmith
@evanh

O.K. so your both saying do the math first then convert each digit to ascii and then print?
• Posts: 662
@ersmith
@evanh

I think I get it. Will work on it.
Thanks
• Posts: 425
pilot0315 wrote: »
@ersmith
@evanh

O.K. so your both saying do the math first then convert each digit to ascii and then print?

Yes, trying to perform maths on the ASCII version is a painful thought.
• Posts: 662
@evanh
@ersmith

Having so much fun with this.
copied both codes into the program ran seperate. Got gobbydiguk in the serial terminal. I am lol.
Well I tried a couple of things and oh well THE FORCE IS NOT WITH ME AT THIS TIME.
I will continue, with your help,to :do there is no try.

thanks

I do understand the dec to ascii method but what happended.
thanks
• Posts: 11,635
edited 2019-11-29 08:49
Start by changing all those RES 1's into LONG 0's. RES, contrary to its apparent naming, does not reserve any memory space.

EDIT: The alternative is to place them all at the end of cog code, just before the ORGH. RES doesn't apply to hubRAM.

EDIT2: Assembling it, Fastspin correctly indicates a couple of typo's, at lines 75 and 112.

• Posts: 662
@evanh
Fixed the typo's thanks. opened in flexgui to find them. No line numbers in Pnut?
It appears somewhat better. Was able to print the decimal, attempted to add and print, no go.
Put the mov number,#1 above the loop and tried to add in the loop. Not working.
I think I understand the ascii conversion math now remembering having seen it before, will review it for better understanding.
This is my deepest foray into asm programming, but slowly getting it.
Here is the code.

Thanks again
• Posts: 11,635
edited 2019-11-30 00:34
Okay, I think I've got it doing what you wanted. Probably did more clean up than I should have but the key changes weren't huge. Deleted a few lines that weren't useful. Put a RET instruction at end of dec_to_ascii routine - not sure how it wasn't crashing without that. Corrected a couple of PA vs PB differences between the two serial emit routines: putchar and send_char.
• Posts: 662
@evanh

Yes thank you. I will study it.
Been trying for over a year to learn assembly language. Started on the P1. To me it made no sense, as I saw in
were more like "Look what I can do" and forgot that most were not as knowlegable.
So with some help from parallax and others I wrote a basic tutorial for myself and shared it, in the forums of P1 to do basic math from spin to pasm and back.
Was and will continue it plus add P2.
Learning how to get in and out of with basic math to me makes more sense.
I will study your code lesson and do other math. I understand it better now.
• Posts: 11,635
I learnt more from understanding CPU architectures than I did from say computer science or any software tutorials.

My first year working I was privileged to be sent on a one week block course where we got taught about the guts of a mini computer - retired NCR equipment. The different sections of the CPU were contained across four large (8U maybe) slotted boards with hand assembled wirewrap interconnect on the backplane. The most complex single component would have been an LSI adder chip. It had a few kBytes of of core memory on another board. Most of the rest was stripped out I think. There wasn't any peripherals like printer or terminals or even storage.

It had hand operated register loading and stepping switch panel and also board extenders so a scope could be used on any component. Along with the tutor's diagrams of interconnect, the ways an address can be generated for example, the visuals of doing that really sank in.

The other minor revelation came with a disassembler/monitor/debugger tool for the Amstrad CPC. It showed me the clear distinction between opcodes and operands on the Z80. Which are not so distinct with RISC architectures like the Propeller.
• Posts: 17,949
@pilot0315,
IMHO you would be better learning using a P1. There is both spin and PASM available.

Spin is a higher lever language but it is fairly straight forward for the basics. It enforces indentation which is something all good programmers should do as it makes the code easier to read.

P1 PASM is a regular instruction set. The P2 contains many other extra instructions that are not regular, and that makes it much more complex for the beginner.

You would be much better learning the basics first. P1 is one of the best micros of the modern era to learn on IMHO due to its' simple regular instruction set, and no interrupts. Initially forget about cogs (cpu cores). Just write simple programs and extend these to doing things more complex. There are plenty of code examples in OBEX.
Learn to use objects such as FullDuplexSerial, one of the Video objects (I wrote the 1-pin TV and Keyboard which I think is well documented), and maybe one of the PS2 Keyboard routines. Use them first - worry about how they work later because often you will find the objects utilise tricks and quirks which make understanding them from the beginners point of view not only difficult, but confuses the learning process. DO NOT try to understand FullDuplexSerial - it's way too difficult for the beginner.

Once you can output to FullDuplexSerial (often called FDX - and use Parallax Serial Terminal PST on the Windows PC), and your choice of TV/VGA then you can write your programs to output various debug messages to those devices and this will help you to debug your own programs - and you'll learn more and faster.

BTW FDX has routines to output all types of data from characters, strings, hex, decimal, binary.

• Posts: 662
@evanh

Understanding the dec to ascii, actually pretty simple.
I copied over everything to an earlier iteration so that I can understand what is going on.
I commented out "itod" and just got the integer adding.
• Posts: 662
@Cluso99

Thanks, I am getting better at this. It is challenging but I will continue. Spin is no problem I am good at it, Prop C no problem, taught my self in 6 months. Asm language is my SUDOKU.
I have been using the P1 for over ten years. Written tons of code.
Appreciate your, and everyone elses, @evanh 's help simplified and clarified what was going on, so I now understand how to print from P2asm which has jumpstarted me. Once I get the math done I will be able to move on.

It is great reading the forums and all of the different projects. I am learning a lot from them.

Thanks
@Cluso99
and @evanh
• Posts: 662
@evanh

The addition printing works great. I tried subtraction and got something weird.
Starting at 100 and subtracting 1.
Got what is in the picture. Subtractions is working but where did the numbers on the left come from?
Changed the baudlen from one to 10 progressively and the numbers that show up become zero but the code correctly
subtracts.
Is there something special that I have to do to set it up?

Thanks
• Posts: 11,635
edited 2019-12-09 06:22
It's because the itod routine can't handle bcdlen = 0. You've jumped over the setting of bcdlen.
EDIT: Err, no, I got that wrong, I wasn't looking too hard.

Not sure. Looks to be a bug in handling of very large numbers. The first case is zero, second case is zero minus one which is unsigned rollover to 4294967295. And each case after is one less.

EDIT2: Ah, worked it out. I had an unclear arrangement hidden in the variables used for that itod routine. In its original setup it relied on overlaying the BCD string across two longwords that were known to be available if they weren't rearranged. But, of course, you do have a rearranged setup so that the longer string at rollover is overwriting bcdlen and messing up the emit length.

Quick fix, use this for your variables:
```ax              long   1
number          long     1
bcdi long 1
bcdlen long 1
bcdstr res 2   'overlays digit1/2
digit1 long 1
digit2 long 1

```
• Posts: 662
@evanh

Howdy, sorry been busy had a two week break from my regular job.
I will try the changes above and let you know.

Been hacking a Coji that I found in a thrift shop and gonna run it with the P2 kind of over kill should be running shortly.
Gonna try to use up all cogs.

coji.jpg 232.6K
• Posts: 11,635
Lol, good idea. The software on those type toys are usually utter rubbish.
• Posts: 662
@evanh
Changed the variables.
If the minuend is 100 and the subtrahend is 1 where does the :4294967242 etc. come from?

I coded for 100 - 1 to print the difference:
99
98
97
etc.

Thanks
• Posts: 11,635
edited 2020-01-25 23:36
That's the 32-bit unsigned circular rollover. It's part of what's known as "two's complement" encoding.

For ease of example, take all the numbers, in order, that can fit into two bits: 00, 01, 10, 11. In unsigned decimal format that is written as 0, 1, 2, 3. If you add one to 11 (3) it will roll over back to 00 (0). Or if you subtract one from 00 {0} it will roll over back to 11 (3).

If those were instead written as signed decimal format then they would be 0, 1, -2, -1 respectively. And adding one to 11 (-1) making 00 (0), is not a rollover. Instead, signed interpretation is not treated as circular and therefore crossing the negative, 10, to positive, 01, boundary is treated as an overflow error, even though the ALU maths doesn't make any distinction because it always uses circular maths. Ie: The two's-complement ALU handles both with different flags and it's up to the software to decided whether to treat the results as unsigned circular or signed linear.

There is DSP's that can hardware bound the maths, for the purpose of clipping a PCM encoded waveform. FPU's also have quite different rules.

EDIT: Corrected the numbers for negative overflow example.
• Posts: 11,635
There is a proposed replacement for floats, called posits, which also uses a signed circular model like two's complement.
• Posts: 662
@evanh
O.K. thats kool, but how do I convert it. I looked around the net, getting the drift. What do I do with this?

Thanks.

BTW I uploaded the wrong code that produced this. I now have the correct code loaded in the previous post.

Thanks
• Posts: 11,635
edited 2020-01-26 00:41
pilot0315 wrote: »
BTW I uploaded the wrong code that produced this. I now have the correct code loaded in the previous post.
You've still got the bug with "bcdstr". To fix it, just replace those definitions of variables with the following:
```ax              long   1
number          long     1
bcdlen long 1
bcdi long 1
bcdstr  res 2
digit1 long 1
digit2 long 1
```

And there is also a bug with a missing "#" in the "putnline" routine too. Here's the fixed version:
```putnline
mov   pa,  #13
call #send_char
mov pa, #10
jmp #send_char
```
• Posts: 11,635
pilot0315 wrote: »
O.K. thats kool, but how do I convert it. I looked around the net, getting the drift. What do I do with this?
They're perfectly okay as they are. Depends what you want done. What sort of job are these numbers going to be used for? Do you want to print the numbers as signed rather than unsigned? Do you want to use floating point instead of integers?
• Posts: 11,635
I'll have another shot at more clarification on the number print routines. In your "dec_to_ascii" routine it contains two steps:
- First step is separate out two 0-9 integers from the one 32-bit (32 binary digits) two's-complement integer. These represent two decimal digits but are still stored in a 32-bit binary memory each.
```   qdiv  number, #10  ' divide number by 10
getqy digit2       ' get remainder
getqx digit1       ' get number/10; we assume it is < 10, if not we would have to iterate
```

- Second step is add the ASCII character offset to each decimal value and emit them out the comport one character at a time. Each character represents a decimal digit.
```   add   digit1, #"0" ' convert digit1 to ASCII
mov   pa, digit1   ' print first digit
call  #send_char
mov   pa, digit2   ' print second digit
call  #send_char
```

So you can see why I've called mine "itod" - short for integer-to-decimal, since it emits the decimal representation of an integer. The integer itself doesn't change.

In another world, pocket calculators for example, the numbers are stored as BCD rather than two's-complement integers. So that would be a different solution. Or with FPU's the numbers are stored as IEEE floats.

• Posts: 662
Thanks I looked at a couple of websites. Now understand. Have to seperate each digit and convert to ascii. Then print them in a "string" individually to get the results.

Like this:

convert 213 into ASCII code,just add 48 to 2 then 48 to 1 and lastly 48 to three

So we get 50 49 51. Now I understand. Then send each character at a time.

Thanks
• Posts: 11,635