6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Apr 27, 2024 9:53 am

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Mon Jan 01, 2024 7:04 pm 
Offline

Joined: Mon Jan 01, 2024 6:24 pm
Posts: 3
Hi - I'm largely a newbie to assembly language, so apologies for poor terminology etc!

Context - I've built a Ben Eater style 65C02 style computer ( on breadboards although changing over to a PCB shortly) which works fine. I want to eventually be able to display temperature and set myself the challenge of using the DS18B20. I have been using the http://6502.org/mini-projects/ds1820/ds1820.htm code by Leo Nechaev to help. I am using retroassembler as the assembler (as an extension to Visual Studio Code

Story so far - I have been working through Leo's code ( adapting as appropriate) and really trying to make sure that I really understand the code, rather than simply blind copying and thus far have been fairly successful - to the point that I can communicate with the device , "ask" it to measure temperature and then send the appropriate pulses to command it to provide the 16 bit temperature - and I since I have an oscilloscope connected to the VIA port that I am using it is responding and the data it is sending back makes sense with respect to the expected temperature.

The problem(s). The main issue is understanding the code that reads the returned bit(s) from the device, which is as follows.

tmpRead ; reading byte from the device
ldx #8 ; 8 times
- pha
jsr tmpReadBit
pla
ror ; bit-by-bit (in carry)
dex
bne -
rts

tmpReadBit
jsr tmpSetZero
jsr tmpSetOne
lda rgConfig
asl
php
jsr tmpDelay
jsr tmpDelay
jsr tmpDelay
jsr tmpWaitForReady
plp
rts

As I see it, when a bit is read in the tmpReadBit subroutine after sending the ready pulse, the next opcode is asl. So if the bit read was a 1, this will be stored in the accumulator and then shifted left to bit1 and bit0 replaced by a 0. The carry flag will not be set. We then jump back to the tmpRead subroutine which then applies ror to the accumulator - which appears in this case to be the reverse of the asl opcode as there is no carry flag that could have put a 1 in the bit 7. As you can see the comments indicate that the byte is built up bit by bit (in carry), but I can't see how this works!

The second, albeit less vexing issue is right at the top of the code is

Registers defining:

rgConfig = $6000 ; Write: D7 - output open drain pin with inversion
rgStatus = $6000 ; Read: D7 - input pin without inversion

Now I know that this is changing the pin on the VIA from read to write ( which I achieve with a subroutine) but how does the programme know that rgConfig is write and rgStatus is read when both appear to point to the same memory location ( which again I assume is pointing to the DDR on the VIA)?

Once again apologies for the complete Noob description, but I am hoping that there is someone who understands what I am asking and can point me in the correct direction.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 01, 2024 9:36 pm 
Offline

Joined: Fri Apr 15, 2016 1:03 am
Posts: 135
Main issue:
I think you have the DS18B20 connected to Bit7 of PortB of the VIA.
After
lda rgConfig
runs, A will contain your data bit from the DS18B20 in Bit7, not Bit0. The
asl
will move your data bit into the carry flag.


2nd issue:
The comments on
rgConfig = $6000 ; Write: D7 - output open drain pin with inversion
rgStatus = $6000 ; Read: D7 - input pin without inversion
seem misleading.
They both point to the Port B data register in the VIA.
They could be used interchangeably in the source - the
lda rgConfig
is reading from what the comments say is a write register!

The plan seems to be:
All bits of Port B on the VIA are set to output (to run the LCD) and not changed later.
The CPU can set Bit7 hi or lo as it desires by writing the Port B data register in the VIA.
The DS18B20 can pull this line down even if the CPU has set it hi. The CPU can see this by reading the Port B data register because of the way Port B in the VIA works.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 02, 2024 2:59 pm 
Offline
User avatar

Joined: Wed Feb 13, 2013 1:38 pm
Posts: 586
Location: Michigan, USA
I wonder if Leo's code has a typo'? In my experience (PIC & Atmel) I toggle the data direction register bit while leaving the port latch bit set to '0'. I've attached a quick-n'-dirty port to 65C02 code for a couple of the low-level onewire read/write routines that I use (caveat: untested 65C02 code). Also note that Leo's code is for DS1820 / DS18S20 devices which default to a 9-bit sign extended two's complement temperature value (0.5 degree resolution) while the DS18B20 produces a 12-bit value (0.0625 degree resolution). However, one of the bytes in the 9-byte 'scratchpad' is a 'count_remain' byte (0..15) which can be used to convert a 9-bit DS1820 raw temperature value to a 12-bit value.

If it helps... Here's how I convert the raw temperature value into 10F or 10C, though I'm sure there are probably much better ways to do it;

Code:
    /*                                                                *
     *  the 16C term in the formulas below is the raw Celsius * 16    *
     *  temperature data in the 'temp16' variable.  a rounded value   *
     *  of °C*10 or °F*10 is used for display with a decimal point    *
     *  inserted before the last (tenths) digit.                      *
     *                                                                *
     *  10C = 8C + 2C = 16C/2 + (16C+4)/8                             *
     *                                                                *
     *  10F = 18C + 320 = 16C + 2C + 320 = 16C + (16C+4)/8 + 320      *
     *                                                                */
       bin = rawtemp16;         // calculate common '2C' term first
       bin += 4;                // rounding
       bin /= 8;                // now bin = '2C' (rounded)
       if(flags.7)              // Rt arrow flag = 1 --> Fahrenheit
       { bin += rawtemp16;      // now bin = 16C + 2C
         bin += 320;            // now bin = 18C + 320 = 10F
       }                        //
       else                     // Rt arrow flag = 0 --> Celsius
       { rawtemp16 /= 2;        // now rawtemp16 = 8C
         bin += rawtemp16;      // now bin = 8C + 2C = 10C
       }                        //
       if(negflag = bin.15)     // set/clear "negflag", if negative
         bin = -bin;            // twos complement the temperature
    /*                                                                *
     *  convert 16-bit binary 'bin' to four digit packed bcd in the   *
     *  16-bit 'bcd' variable, then update the display.               *
     *                                                                */


Good luck with your project. Happy new year. Mike


Attachments:
ds18b20_test.s.txt [8.21 KiB]
Downloaded 27 times
Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 02, 2024 6:23 pm 
Offline

Joined: Mon Jan 01, 2024 6:24 pm
Posts: 3
leepivonka wrote:
Main issue:
I think you have the DS18B20 connected to Bit7 of PortB of the VIA.
After
lda rgConfig
runs, A will contain your data bit from the DS18B20 in Bit7, not Bit0. The
asl
will move your data bit into the carry flag.


2nd issue:
The comments on
rgConfig = $6000 ; Write: D7 - output open drain pin with inversion
rgStatus = $6000 ; Read: D7 - input pin without inversion
seem misleading.
They both point to the Port B data register in the VIA.
They could be used interchangeably in the source - the
lda rgConfig
is reading from what the comments say is a write register!

The plan seems to be:
All bits of Port B on the VIA are set to output (to run the LCD) and not changed later.
The CPU can set Bit7 hi or lo as it desires by writing the Port B data register in the VIA.
The DS18B20 can pull this line down even if the CPU has set it hi. The CPU can see this by reading the Port B data register because of the way Port B in the VIA works.


Thanks so much for your reply - and of course it allowed me to have the "doh" moment! In fact I am using port A1 on the VIA. So stupidly I had expected a "1" to look like %00000001, whereas in my case it will be on bit 6, thus %01000000. I can go back and play now.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 02, 2024 6:27 pm 
Offline

Joined: Mon Jan 01, 2024 6:24 pm
Posts: 3
Michael wrote:
I wonder if Leo's code has a typo'? In my experience (PIC & Atmel) I toggle the data direction register bit while leaving the port latch bit set to '0'. I've attached a quick-n'-dirty port to 65C02 code for a couple of the low-level onewire read/write routines that I use (caveat: untested 65C02 code). Also note that Leo's code is for DS1820 / DS18S20 devices which default to a 9-bit sign extended two's complement temperature value (0.5 degree resolution) while the DS18B20 produces a 12-bit value (0.0625 degree resolution). However, one of the bytes in the 9-byte 'scratchpad' is a 'count_remain' byte (0..15) which can be used to convert a 9-bit DS1820 raw temperature value to a 12-bit value.

If it helps... Here's how I convert the raw temperature value into 10F or 10C, though I'm sure there are probably much better ways to do it;

Code:
    /*                                                                *
     *  the 16C term in the formulas below is the raw Celsius * 16    *
     *  temperature data in the 'temp16' variable.  a rounded value   *
     *  of °C*10 or °F*10 is used for display with a decimal point    *
     *  inserted before the last (tenths) digit.                      *
     *                                                                *
     *  10C = 8C + 2C = 16C/2 + (16C+4)/8                             *
     *                                                                *
     *  10F = 18C + 320 = 16C + 2C + 320 = 16C + (16C+4)/8 + 320      *
     *                                                                */
       bin = rawtemp16;         // calculate common '2C' term first
       bin += 4;                // rounding
       bin /= 8;                // now bin = '2C' (rounded)
       if(flags.7)              // Rt arrow flag = 1 --> Fahrenheit
       { bin += rawtemp16;      // now bin = 16C + 2C
         bin += 320;            // now bin = 18C + 320 = 10F
       }                        //
       else                     // Rt arrow flag = 0 --> Celsius
       { rawtemp16 /= 2;        // now rawtemp16 = 8C
         bin += rawtemp16;      // now bin = 8C + 2C = 10C
       }                        //
       if(negflag = bin.15)     // set/clear "negflag", if negative
         bin = -bin;            // twos complement the temperature
    /*                                                                *
     *  convert 16-bit binary 'bin' to four digit packed bcd in the   *
     *  16-bit 'bcd' variable, then update the display.               *
     *                                                                */


Good luck with your project. Happy new year. Mike



Thanks Mike - I had wondered the difference between the DS18B20 and the DS1820 but knew at least that the former could go up to an impressive resolution from reading the datasheet. My intention was to go back and programme it to give me just the 9bits, but only after I had sorted the read bits subroutine. I will certainly borrow your code for the conversion, although I have still got a bit to go before getting there.

Happy New Year as well

Roddy


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 19 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: