More problems trying to get SOMO to work...

Grogster

Senior Member
Hi all. :)

Code is pretty much exactly the same as the working code I was using on the 14M2 a year or so ago, but it refuses to co-operate.

I suspect I have done something wrong, when porting the code to the 40X2 chip.

Here is the code that is supposed to work:

Code:
'SOMO tester code thing
'VErsion 1A

#picaxe 40x2
#no_data
#no_table

symbol control=b0	'Used for control bits - don't use for anything else
symbol dta=w6	'Data to module is a word(16-bit) value
symbol x=b5		'X marks the spot...
symbol mask=bit0	'Mask word for the shiftout proceedure
symbol MSB=$8000	'Most Significant Bit position is bit 16
symbol sda=B.6	'Serial data output is on port B.6
symbol scl=B.7	'Serial clock output is on port B.7

init:
 high scl		'Set clock idle state high
 low sda		'Set data idle state low
 low B.4		'Ensure RESET is allowed to idle-high(548 pull-down transistor NOT active)
 wait 3		'Allow things to start up
 dta=$1C3		'Select track #451
 gosub somo		'Instruct SOMO module to play track represented by value of dta
 high scl		'Set clock idle state high
 low sda		'Set data idle state low
 gosub piezo	'Beep piezo as confirmation of completion of talking to SOMO.
 debug
 
 stop
 
 
 
'================================
'CLOCK DATA TO MODULE SUBROUTINE:
'================================

somo:
  'gosub rst		'Reset module first
  low scl		'Pull clock-line low
  pause 2		'Start-bit time
  for x = 1 to 16	'Start of shiftout code
  mask = dta and MSB / MSB
  low sda
  if mask=0 then skipMSB
  high sda
  
 skipMSB:
  if x = 16 then skippulse
  pulsout scl,20	'100uS minimum pulse-width for clock or data lines
  dta = dta * 2
  
  skippulse:
   next x		'End of shiftout code
   high scl		'Pull clock-line high
   pause 2		'End-bit time
 return
  
'rst:
'  high B.4		'Reset module
'  pause 5		'Reset pulse-width as per manual ver 3.0
'  low B.4		'"Release" reset
'  pause 300		'Reset to first bit wait time as per manual ver 3.0
'  return
  

'=======================
'BEEP PIEZO SUB-ROUTINE:
'=======================

piezo:
 high A.1		'Turn on piezo beeper via 548
 pause 150		'Wait some time
 low A.1		'Turn off piezo beeper via 548
 return
This code returns a value of 32768 for dta, which is REALLY wrong - can someone offer any pointers as to what I have done wrong in the code?

If you set dta to 451(1C3) using dta=$1C3, then once it has clocked that to the module, the debug window should show the value of dta as being 451, but it says it is 32768???? :confused:
 

Grogster

Senior Member
OH yes.

100n SMD cap right on the SOMO power pin, SOMO fed from 3v3 regulator. Regulator decoupled with 470uF input and 470uF output. Input voltage 12v. Regulator type MCP1703-33.
470uF cap right on SOMO power supply pin.

All that was hammered out in the other thread a year or so ago, and as the SOMO is a little touchy about power quality, those caps and regulator were the first parts placed before I laid down any other parts. :D

Do you see any issues with the code port from the 14M2 chip?
I still have the original tester PCB built around the 14M2, and it is working OK running this code, but on the 40X2 it does not want to work.
 

hippy

Ex-Staff (retired)
If you set dta to 451(1C3) using dta=$1C3, then once it has clocked that to the module, the debug window should show the value of dta as being 451, but it says it is 32768???? :confused:
There's a "dta=dta*2" in the code which clocks out the result, so a result of 32768 ($8000) after that is correct for a value which starts with its lsb set.
 

Grogster

Senior Member
I wish I could understand how those routines work - I don't really understand it, which is not helping the situation, as I run into a brick wall if it doesn't just work out of the box. :(

Perhaps some members here can help me understand the maths behind those bit-banging routines...
 

hippy

Ex-Staff (retired)
Do you see any issues with the code port from the 14M2 chip?
I still have the original tester PCB built around the 14M2, and it is working OK running this code, but on the 40X2 it does not want to work.
The obvious difference between an M2 and an X2 is a different default operating speed. There may be timings you need to tweak, particularly PULSOUT.

Does the 14M2 code run with SETFREQ M8 added, does the 40X2 run with SETFREQ M4 added ?
 

Grogster

Senior Member
AHHHHHHH - now THERE'S a point! :)
No, I had not allowed for that, and yes the 14M2 was running at 4MHz, whereas the 40X2 is 8MHz by default - probably where my issue is.

I will keep tinkering...

EDIT: 40X2 does not work with setfreq m4 added.
 

westaust55

Moderator
I believe hippy is on the right track . . .

my suggestion for same reason (X2 default speed is 8 MHz) try this subroutine as the pulse time duration at 8 MHz will be the absolute min by the SOMO 14D datasheet:
Code:
somo:
  'gosub rst		'Reset module first
  low scl		'Pull clock-line low
  pause 2		'Start-bit time
  for x = 1 to 16	'Start of shiftout code
  mask = dta and MSB / MSB
  low sda
  if mask=0 then skipMSB
  high sda
  
 skipMSB:
  if x = 16 then skippulse
  pulsout scl,[B][COLOR="#FF0000"]40[/COLOR][/B]	'100uS [B]minimum[/B] pulse-width for clock or data lines [COLOR="#FF0000"]use 200 us[/COLOR]
  dta = dta * 2
  
  skippulse:
   next x		'End of shiftout code
   high scl		'Pull clock-line high
   pause 2		'End-bit time
 return
The two commands/lines:
PAUSE 2​
are also at the minimum even at 4 MHz clock, so try setting those to
PAUSE 3​
 
Last edited:

Grogster

Senior Member
You are quite right, westaust55(and hippy).

Even with the ORIGINAL 20 value for pulsout, it is still working, but as you say...

Would you believe the REAL reason for nothing wanting to work?

uSD card compatibility problems again. :(

I was using SanDisk 64MB uSD cards, and they would not work.
Knocked it up a cog to 128MB SanDisk card, and everything is working.

I was pretty sure that the 64MB SanDisk cards worked OK on this module, from what I remember of all our testing on that thread a while ago..........
 
Last edited by a moderator:

hippy

Ex-Staff (retired)
There might be some gain of clarity in rewriting the transfer routine using IF-THEN-ELSE structures. Untested ...

Code:
somo:
  'gosub rst		'Reset module first
  low scl		'Pull clock-line low
  pause 2		'Start-bit time
  for x = 1 to 16	'Start of shiftout code
    if dta >= $8000 then
      high sda
    else
      low sda
    end if
    if x <> 16 then
      pulsout scl,40	'100uS minimum pulse-width for clock or data lines use 200 us
      dta = dta * 2
    end if
  next x		'End of shiftout code
  high scl		'Pull clock-line high
  pause 2		'End-bit time
  return
 

Grogster

Senior Member
Hello. :)

hippy's new code seems to work just fine.

I still don't follow HOW that loop works.

Assume that dta=20 when I send it to the loop routine, it would seem you are in trouble by the 13th clock cycle - bad luck?
At cycle 13, the value of dta tries to be 81920. Expanding out the loop so I can see all the numbers:
20 * 2 in the loop(dta=dta*2) for 16 times is: 20,40,80,160,320,640,1280,2560,5120,10240,20480,40960,81920,163840,327680,655360.

When dta tries to be 81920, it will fail. Normally, you would expect this to result in a "Variable out of range" error, so if someone can help me understand how the loop deals with any number bigger then 65536, I think I would then understand how the loop works.

Does it just overflow to 16384 then carry on from there?

If that was the case, then the sequence from the 13th cycle to the 16th cycle would be: 16384,32768,65536,131072

The very lasy cycle cannot be 131072, so overflows to 65536.

The total number sequence in that case would therefore be: 20,40,80,160,320,640,1280,2560,5120,10240,20480,40960,16384,32768,65536,65536

All that translates to 0000000000010111, which is not 20, it is 23. :confused:

I am sure I have something in my figures wrong, so if anyone can help to explain it a bit more, it would help me a lot.
 
Last edited:

AllyCat

Senior Member
Hi,

You're probably confusing youself by trying to consider the word in decimal format, just consider it as a string of 16 bits.

The if dta >= $8000 then reads the "top" (leftmost) bit and acts accordingly.

The dta = dta * 2 shifts the string of 16 bits leftwards by one bit position (arguably dta = dta + dta is slightly more efficient). A '0' is introduced at the right-hand end and the top bit "falls off the (left-hand) end" and is lost (a numerical overflow).

After 16 loops the word will be empty (zero) but the data should have been transmitted correctly. If it's necesary to retain the word value, then either copy it to another word at the start or, at each shift, add '1' (at the RH end) each time an overlow occurs (at the LH end).

Cheers, Alan.

PS: Your analysis in decimal above is correct, except that 65,536 is an overflow (16 1's or $FFFF is 65,535) so becomes simply 0 (zero).
 
Last edited:

westaust55

Moderator
The dta = dta * 2 shifts the string of 16 bits leftwards by one bit position (arguably dta = dta + dta is slightly more efficient).
In terms of adding a number to itself as a means of doubling the value, it will be faster as microcontrollers typically have an ADD incstruction but not a multiply function as a core instruction.
The multiply might be a little clearer that we are trying to double the value but one must still know/realise that we are really still trying to shift one bit to the left.

Think in terms of:
Shifting a bit to the left equates to multiply by 2 (can be done by addition)
Shifting a bit to the right equates to divide by 2 (cannot use subtract to do an equivalent)

Whether we use dta = dta * 2 or dta = dta + dta these are universal in terms of working on all PICAXE chips.

For X1 and X2 parts only there is also the option of:
dta = dta << 1
to shift one bit to the left.
Again a bit shift left or a bit shift right are core PIC instructions and will be faster than multiply and for a 1 bit left/right may be faster than addition - would need to test this.

At the end of the day, when the original code was posted (see link in post 11), I had tried to follow, to some extent, the bit-bashed examples in PICAXE manual 2 under the SHIFTOUT command with a view to keeping things universal and relatively consistent, albeit that I also introduced a bit variable as a flag.
 
Last edited:

westaust55

Moderator
hippy's new code seems to work just fine.
Most likely as a result of the line:
pulsout scl,40
where the pulse duration was increased to accommodate the faster X2 part.

I still don't follow HOW that loop works.
One way to see what is happening and maybe better understand is to use the Programming Editor and run the Simulator using the Step mode.
Set the variable display (open with the >> button if necessary and set the display to word using the check box below the variables.

Then step through the program and watch the value of the word variable dta and the "sda" pin as the loop clocks through for the 16 cycles.

With an X1 or X2 parts, these three permutations will give the same display for the shifting of bits in the word variable dta and the output pin:
dta = dta * 2
dta = dta + dta
dta = dta << 1
 

Grogster

Senior Member
Good idea - was staring me in the face too - must use the simulator and single-stepping more often when I get lost over how code snippets work... ;)

I stepped through the routine very slowly several times, and I understand it now.
 
Top