Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 09:17 01 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Playing around with bits....

Author Message
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 07:55pm 20 Nov 2015
Copy link to clipboard 
Print this post

Hi folks.

In the stereo project that jman is helping me with, he wrote most of the code to manipulate the bits of the data byte for any address that you send off to the pre-amp chip, but I would like to understand how this actually works.

Take the following snippet from the manual:





As you can see, this byte consists of several things you can adjust, those being the input source selector, the input gain, and the AutoZero feature.

I understand how all this changes to get you what you want, but what I DON'T understand, is the mathematics behind how you manipulate the bits of the byte to get the final byte you send off to the device with the settings you want.

Take for example, the case of wanting SE1 input, 3dB input gain and AutoZero off.
This would result in a final byte of &B10011100, or 9Ch(156 decimal).

That's fine, and I follow all that just fine, but the problem I am having is in working out HOW you combine the values into the one byte.

jman used XOR, but I have played with XOR at the command prompt, but it does not render the results I expect, I am obviously not understanding how XOR works as well.

I post this here, rather then pester jman directly, as I thought it might make a useful public discussion, and a chance for others to learn the same thing I am trying to learn etc, etc, etc...

So, getting back to the above example, and going on what I do understand about how binary numbers are powers of two, you therefore have the following values for the byte:

AutoZero=80h(128 decimal)
Gain(3dB)=18h(24 decimal)
Input(SE)=04h(04 decimal)

Adding these together, we correctly come to 9Ch(156 decimal), and all this is fine, and I follow all that.

WHERE I AM LOST: Combining the numbers SIMPLY. You can, naturally, add the numbers up, but if you have to set bit7 in one command, and bits 4 & 5 in another command, and then COMBINE both those into ONE byte, WITHOUT upsetting the bit-positioning of any previous command - this is where I am lost.

Not sure I am explaining it that well, as I don't understand the mathematics involved, so am probably using the wrong terms, but hopefully everyone can see what I mean.

A very simplistic am mathematically incorrect way of demonstrating the above is that you have two bytes in the form of A=&B10000000 and B=&B00011000 - how do you combine those so that you end up with a single byte equal to &B10011000? A XOR B does NOT return the correct result(298h or 664 dec), so I am unwilling to trust this blindly, even though this is how jman is doing some of it.

Another example might be three(or more) values such as in this example:

A=&B10000000
B=&B00011000
C=&B01000000

"Adding" together, I would need the result to be &B11011000.

This bit shifting stuff has me totally confused at the moment.
I know what needs to happen, but I don't understand what mathematics need to happen to do it.

Can anyone help me understand how to do this?

EDIT: Writing things down seems to help clarify to some extent. I think my problem is that I am not remembering to stay in the correct decimal value of things. Take the gain control in the chart above. I see this as 1-15(0001-1111), so adding 3 to the value of the byte DOES NOT render the correct results, as the bits are in the wrong place. Although there are 15 numbers(001-1111), the decimal value range is actually 8-120 using those four bits, but I want to show this on the screen as 0-15dB, and am getting lost in the conversions needed.Edited by Grogster 2015-11-22
Smoke makes things work. When the smoke gets out, it stops!
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 08:16pm 20 Nov 2015
Copy link to clipboard 
Print this post

When working with bits it is best to use BIN as you are doing.
You need to understand the basic BIT operations - AND OR and XOR

AND, if both bits are set (1), the result is 1
OR if either bit is set, the result is 1
XOR if one bit is set (1) and the other not set (0), the result is 1

There is no 'carry' and the operation is done on each bit independently.

try this code:

A=&B10010000
B=&B00011000
C=&B01000000

PRINT BIN$(a,8)
PRINT BIN$(b,8)
PRINT BIN$(c,8)
PRINT ""
PRINT BIN$((a OR b),8)
PRINT BIN$((a AND b),8)
PRINT BIN$((a XOR b),8)
PRINT ""
PRINT BIN$((a OR b OR c),8)
PRINT BIN$((a AND b AND c),8)
PRINT BIN$((a XOR b XOR c),8)
PRINT ""
PRINT BIN$(((a AND b) XOR c),8)
PRINT BIN$((a XOR (b XOR c)),8)


All the BIN$ stuff just makes the code harder to follow but is need to see the results.

When you start working with more than 2 numbers, use brackets so you are certain of the order in which the operations are performed. There are too many correct ways of doing it - it is the sort of thing that starts heated discussion.

JimEdited by TassyJim 2015-11-22
VK7JH
MMedit
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 08:22pm 20 Nov 2015
Copy link to clipboard 
Print this post

  Grogster said  Take for example, the case of wanting SE1 input, 3dB input gain and AutoZero off.
This would result in a final byte of &B10011100, or 9Ch(156 decimal).

According to the table, shouldn't that be &B10011001

I haven't got to the end of your post yet, but hope this isn't the issue
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 08:29pm 20 Nov 2015
Copy link to clipboard 
Print this post

Thanks - will experiment with your demo code.

These are the results I got:





I will play around more with your demo code.
Still lost, but I will persevere.
It would seem that what I need is the ? BIN$((A OR B),8) command?

So therefore, A OR B should give me the combined result, yes?

What if we throw variable C into the mix?
Can you have something like ? A OR B OR C?
I will experiment some more.

Not meaning to start a heated discussion on the best way to do it.
I just want to understand HOW, as I am still lost on this at the moment, and if I just let jman deal with that side of the code, I am not actually learning anything, and this kind of stuff is used on just about any I2C chip for the config bytes, so it is something I would like to understand.
Smoke makes things work. When the smoke gets out, it stops!
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 08:31pm 20 Nov 2015
Copy link to clipboard 
Print this post

  WhiteWizzard said  According to the table, shouldn't that be &B10011001


Yes, it should - typo - sorry.
Smoke makes things work. When the smoke gets out, it stops!
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6283
Posted: 08:39pm 20 Nov 2015
Copy link to clipboard 
Print this post

For your volume, try this code snippet

db = 15
dbBITS = db*8
PRINT BIN$((dbBITS),8)


Ypu would then OR the resulting dbBITS with the other control bits to get the value to sent to the device.

Try it with different values for db

multiplying by 8 is the same as shifting left by 3 bits. 2*2*2

remember, the BIN$ stuff is just so that us mere mortals can see the number in binary. The computer doesn't care.

"Can you have something like ? A OR B OR C?"
See my first (amended) post .

Jim
VK7JH
MMedit
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 08:41pm 20 Nov 2015
Copy link to clipboard 
Print this post

Ahhhh - I think I am making slow progress.

Some experiments:





If I OR anything together, this would seem to put the bits where I need them.
I don't know if this is just because of the way I have setup my example or not though.
Smoke makes things work. When the smoke gets out, it stops!
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 09:14pm 20 Nov 2015
Copy link to clipboard 
Print this post

OK - there are many ways to get the end result - however, you have specifically asked about a 'simple' way of 'adding' the numbers.

My approach would be (based on the example chart) to have three variables representing AutoZero (0-1), Input Gain (0-15), and Source (0-7).

So each of these three variables take on only one of their possible values. The approach is then set/change any variable, then call one common sub to 'compile' the resultant byte.

So to compile the resultant byte (call it x, and initially set x=0) the AutoZero value (0 or 1) needs to be multiplied by 128 (or shifted 7 bits left), and then OR'd with x (or added to x), the Input Gain multiplied by 8 (or shifted 3 bits left) and OR'd with x, and the Source left as it is and OR'd with x.

If you now wanted to go from 3dB to 2dB you need to change ALL the relevant bits in the byte i.e. for gain, bits D3, D4, D5, and D6; while leaving all other bits (i.e. other functions) untouched. This is where I think you are after a 'simple' way to do it.

Again, many ways to do this including masking, XORING, shifting. But I would simply call the same routine I outlined above which will then adopt any change in value in any of the three functions.

The above approach is useful when you have a variable/feature that takes on a 'direct' binary value such as the input gain. So here, the binary range is 0000-1111 which represents a 'human' range of 0-15.

The approach above allows you to keep a variable called InGain to a human readable number of 0-15 which makes the code nice and easy to read.

However, all that said, if you several 'features' in a byte that have no 'human' meaning (typically one or two bits in the byte), I would store these as binary values. So in the above example, AutoZero would be &B10000000.

Then this becomes like your 'A,B,C example you gave where all you need to do is OR the bytes together to initially compile the result (or add them together as you put it!). Now to change a 'section' of the byte without altering other functions/bits the approach I would use is a two step process: First to mask out (with AND), then OR the channge to get the result.

So going from 3dB to 2dB:

&B1 0011 001 Initial byte value (AutoZero, 3dB, SE1)
&B1 0000 111 (mask out the function changing by ANDing with this)
------------
=B1 0000 001
B0 0010 000 (OR with the new Gain required)
------------
&B1 0010 001 (AutoZero, 2dB, SE1)

Now define simple!!! I personally prefer the three variables, one sub method!
 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2944
Posted: 09:17pm 20 Nov 2015
Copy link to clipboard 
Print this post

Blimey, that took me a long time to type - been lots of posts since I started typing

Hopefully it will make sense soon
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4044
Posted: 09:37pm 20 Nov 2015
Copy link to clipboard 
Print this post

Quick tip: XOR is not used much. (Except in e.g. CRC calculations if you do any.)

Another: to set a few bits (like the bottom 3 in your example) to a specific pattern, you often want to zero them out then OR in the pattern (the new setting). Deleting (zeroing) bits is an AND NOT. In this case you'd want to AND with NOT &B111. The idea of NOT is to invert each bit. So, you'd AND with &B11111000. It keeps all the bits where the 1s are and zeroes all the bits where 0s are.

(In case MMBasic doesn't do NOT like this, you can make a function.)

John
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 10:02pm 20 Nov 2015
Copy link to clipboard 
Print this post

@ WhiteWizzard - Thanks for your long post, and it was very helpful too. I am inclined to agree with your way of thinking(as it is my way of thinking too), in that you have a sub to compile the byte. I too look at each separate parameter as numbers within the control range, and not the actual value of the bits within the byte - that was also a source of my confusion.

@ everyone - I am going to run several other experimental test codes to help me understand this better. I will post back with any issues I have, and I expect to have some, as I am learning something new to me here.....

Smoke makes things work. When the smoke gets out, it stops!
 
Chris Roper
Senior Member

Joined: 19/05/2015
Location: South Africa
Posts: 280
Posted: 10:29pm 20 Nov 2015
Copy link to clipboard 
Print this post

  JohnS said   Quick tip: XOR is not used much. (Except in e.g. CRC calculations if you do any.)...
John


I respectfully disagree John

XOR is probably the most used logic function in embedded applications, primarily for its ability to toggle one or more bits in a byte or a Port. Maybe not so relevant in MMbasic, but I use it often on the 8 bit PIC devices.

Cheers
Chris

http://caroper.blogspot.com/
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 12:25am 21 Nov 2015
Copy link to clipboard 
Print this post

UPDATE

I have some simple code working now, and I think this is the way I will proceed forward - some of you will not agree with this method, but I can understand it when done this way.

Here is a section of the ROHM processor manual:





My experimental code:


'Amp-A-Mite 2A (Rohm processor)
'November/December 2015.


Const RELAYS=&H57 'Relay control board I2C address
'---------------------
'GENERAL APU CONSTANTS
'---------------------
Const APU=&H80 'Audio Processor Unit I2C address(BD37534FV)
Const APU_INI1=&H01 'Initial setup byte #1
Const APU_INI2=&H02 'Initial setup byte #2
Const APU_INI3=&H03 'Initial setup byte #3
Const APU_SEL=&H05 'Input selector
Const APU_GAIN=&H06 'Input gain
Const APU_VOL=&H20 'Volume gain
Const APU_LF=&H28 'Left Front fader
Const APU_RF=&H29 'Right Front fader
Const APU_LR=&H2A 'Left Rear fader
Const APU_RR=&H2B 'Right Rear fader
Const APU_SW=&H2C 'Subwoofer fader
Const APU_BASS=&H41 'Bass control
Const APU_MID=&H44 'Middle control
Const APU_TREB=&H47 'Treble control
Const APU_BG=&H51 'Bass gain
Const APU_MG=&H54 'Middle gain
Const APU_TG=&H57 'Treble gain
Const APU_LG=&H75 'Loudness gain
Const APU_RST=&HFE 'APU reset
'---------------------
'APU CONTROL CONSTANTS
'---------------------
Const APU_ASM0.6=&H00 'Advanced Switch Time(MUTE) 0.6ms(00 dec)
Const APU_ASM1.0=&H01 'Advanced Switch Time(MUTE) 1.0ms(01 dec)
Const APU_ASM1.4=&H02 'Advanced Switch Time(MUTE) 1.4ms(02 dec)
Const APU_ASM3.2=&H03 'Advanced Switch Time(MUTE) 3.2ms(03 dec)
Const APU_ASI4.7=&H00 'Advanced Switch Time(INPUT) 4.7ms(00 dec)
Const APU_ASI7.1=&H10 'Advanced Switch Time(INPUT) 7.1ms(16 dec)
Const APU_ASI11.2=&H20 'Advanced Switch Time(INPUT) 11.2ms(32 dec)
Const APU_ASI14.4=&H30 'Advanced Switch Time(INPUT) 14.4ms(48 dec)
Const APU_AS0=&H00 'Advanced Switch off (00 dec)
Const APU_AS1=&H80 'Advanced Switch On (128 dec)


Start:
Print "MUTE TIME:"
Print "1-0.6, 2-1.0, 3-1.4, 4-3.2"
Input A
If A<1 Or A>4 Then GoTo Start
Print A
Select Case A
Case 1
MT=APU_ASM0.6
Case 2
MT=APU_ASM1.0
Case 3
MT=APU_ASM1.4
Case 4
MT=APU_ASM3.2
End Select
Print
Print "SWITCH TIME:"
Print "1-4.7, 2-7.1, 3-11.2, 4-14.4"
Input B
If B<1 Or B>4 Then GoTo Start
Print B
Select Case B
Case 1
ST=APU_ASI4.7
Case 2
ST=APU_ASI7.1
Case 3
ST=APU_ASI11.2
Case 4
ST=APU_ASI14.4
End Select
Print
Print "ADVANCED SWITCH:"
Print "1-ON, 2-OFF"
Input C
If C<1 Or C>2 Then GoTo Start
Print C
Select Case C
Case 1
ASS=APU_AS1
Case 2
ASS=APU_AS0
End Select
Print
Print "Current byte is:";
BITE=(MT Or ST Or ASS)+4
Print Bin$(BITE,8), Str$(BITE)+" DECIMAL."
End


Done this way, with lots of constants, I can just easily or them together as discussed, and this seems to be working fine for building the data byte. The line that builds BITE, has "+4" on the end, as the data byte always has bit2 set for this command, and that also seems to be giving the correct results.





As I am keeping all the values in constants, there is no need for a sub to compile the byte as it can be done easily in one line.

I am looking into storing all this data in an array rather then pages of constant commands.

The experimenting continues.....Edited by Grogster 2015-11-22
Smoke makes things work. When the smoke gets out, it stops!
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4044
Posted: 04:10am 21 Nov 2015
Copy link to clipboard 
Print this post

  Chris Roper said  
  JohnS said   Quick tip: XOR is not used much. (Except in e.g. CRC calculations if you do any.)...
John


I respectfully disagree John

XOR is probably the most used logic function in embedded applications, primarily for its ability to toggle one or more bits in a byte or a Port. Maybe not so relevant in MMbasic, but I use it often on the 8 bit PIC devices.

Cheers
Chris
Because this thread is about MMBASIC I did not put "not used much from MMBASIC" but that is what I meant.

If MMBASIC had direct I/O port access at the source code level and if people usually accessed I/O ports directly then I might (*) agree with you. But none of those things apply here...

(*) actually, for PIC32 I probably wouldn't due to the CLR, SET & INV ports

JohnEdited by JohnS 2015-11-22
 
Chris Roper
Senior Member

Joined: 19/05/2015
Location: South Africa
Posts: 280
Posted: 04:38am 21 Nov 2015
Copy link to clipboard 
Print this post

  JohnS said  (*) actually, for PIC32 I probably wouldn't due to the CLR, SET & INV ports

John


Agreed, that is why I specifically mentioned the 8 Bit PIC's.
But if anyone is going to get to grips with Bit Manipulation and logic Functions they may as well look at XOR at the same time. Non of us stay on one platform forever and knowledge is portable.

Cheers
Chris

http://caroper.blogspot.com/
 
vegipete

Guru

Joined: 29/01/2013
Location: Canada
Posts: 1132
Posted: 08:39am 24 Nov 2015
Copy link to clipboard 
Print this post

  Grogster said  
BITE=(MT Or ST Or ASS)+4
Maybe you should change the variable "MT" to "MY" and change "ST" to "SORE".

The OR function is much like adding with no carry. So
BITE=MT + ST + ASS + 4
should give the result you want too, assuming there is no bit overlap between the variable. This is dangerous though, because, for example, 8 OR 8 = 8 whereas 8 + 8 = 16, a vastly different bit pattern.

So your BITE MY SORE ... should be coded as
BITE=MT Or ST Or ASS Or 4

Visit Vegipete's *Mite Library for cool programs.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9610
Posted: 02:22pm 24 Nov 2015
Copy link to clipboard 
Print this post

  vegipete said  
  Grogster said  
BITE=(MT Or ST Or ASS)+4
Maybe you should change the variable "MT" to "MY" and change "ST" to "SORE".


Bite my sore ass?

Oh, you people.....

Smoke makes things work. When the smoke gets out, it stops!
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025