Jump to content

ASM and C: Random writes to memory


wackazong

Recommended Posts

Hi,

I have a strange bug using an ASM function in a C applikation: When I call the ASM function, random values get written into the variable RAM. I would be very glad if somebody could have a look a the header and main file, I cannot find the problem...

The header file

/*
 */

#ifndef _KNOEPFLI_ASM_H
#define _KNOEPFLI_ASM_H

/////////////////////////////////////////////////////////////////////////////
// Prototypes
/////////////////////////////////////////////////////////////////////////////
extern unsigned char KNOEPFLI_Interpolate(unsigned char step, unsigned char val1, unsigned char val2) __wparam;

#endif /* _KNOEPFLI_ASM_H */
The main file
	radix	dec

#include <mios.h>
#include <mios_vectors.inc>
#include <macros.h>

; ==========================================================================
; Define constants
; ==========================================================================

; ==========================================================================
; Import/Export Labels
; ==========================================================================

; export labels

	global	_KNOEPFLI_Interpolate		; (for C, )

; ==========================================================================
;  Declare variables 
; ==========================================================================

accessram					udata
pca9635_StepCounter			res		1		
pca9635_Temp				res		1

; ==========================================================================
; Start code section and include driver code
; ==========================================================================
KNOEPFLI_ASM CODE
; ==========================================================================

;; --------------------------------------------------------------------------
;;  FUNCTION: KNOEPFLI_Interpolate	
;;  C_DECLARATION: void KNOEPFLI_Interpolate(unsigned char step, unsigned char val1, unsigned char val2)
;;  DESCRIPTION: Testing the interpolation algorithm: interpolate between  value 1 and value 2 in
;;				 16 steps and return the corresponding step value.
;;
;;  C IN:	step number			in step (through WREG, using __wparam)
;;			value 1				in val1
;;			value 2				in val2
;;
;;  C OUT:	interpolated value as unsigned char (through WREG __wparam)
;;
;;  USES:	MIOS_PARAMETER3
;; --------------------------------------------------------------------------
_KNOEPFLI_Interpolate	
KNOEPFLI_Interpolate	

	;save step value in variable
	movwf	pca9635_StepCounter

	movff	FSR0L, FSR2L		; get other arguments from stack
 	movff	PREINC2, MIOS_PARAMETER1
 	movff	PREINC2, MIOS_PARAMETER2

	;find out if we have to swap the values
	;move MIOS_PARAMETER1 into W
	movf	MIOS_PARAMETER2, W
	;compare, skip the swap if MIOS_PARAMETER2 > MIOS_PARAMETER1
	cpfsgt	MIOS_PARAMETER1
	rgoto	pca9635_interpolate_NoSwap

	;we just swap the values and invert the step counter
	;using a temporary variable
	movff	MIOS_PARAMETER1, pca9635_Temp
	movff	MIOS_PARAMETER2, MIOS_PARAMETER1
	movff	pca9635_Temp, MIOS_PARAMETER2
	;invert the step counter and delete the upper nibble (for four bit counter)
	comf	pca9635_StepCounter, F
	movlw	0x0f
	andwf	pca9635_StepCounter, F

pca9635_interpolate_NoSwap

	;now find the difference between MIDI_PARAMETER1 and MIDI_PARAMETER2
	;load MIDI_PARAMETER1 into W
	movf	MIOS_PARAMETER1, W
	;subtract W from MIOS_PARAMETER2, store result in W
	subwf	MIOS_PARAMETER2, W
	;add 1 for rounding errors
	addlw	1

	;now divide this value by the number of steps
	;because the next operation is a floating point 16bit calculaton, we leave it
	;as it is and take away the decimals later

	;to get the result in the upper byte PRODH, shift the step
	;counter four to the left (for 4-bit counter)

	rlncf	pca9635_StepCounter, F
	rlncf	pca9635_StepCounter, F
	rlncf	pca9635_StepCounter, F
	rlncf	pca9635_StepCounter, F

	;therefore, multiply the difference with the number of steps
	mulwf	pca9635_StepCounter

	;now we just need to get the high byte
	movf	PRODH, W

	;add the MIOS_PARAMETER1 (the low value)
	addwf	MIOS_PARAMETER1, W

	return

; ==========================================================================
	END

When I run the function, another array in my program gets values written into it, and I don't know why. Any tips for how to debug something like this?

The array that gets written into is passed as the first parameter value (not the array, but one part of it, of course, like array ).

Thanks, ALEXander.

Link to comment
Share on other sites

The variables are probably not located in the ACCESS bank -> use SET_BSR to select the bank, add ", BANKED" after instructions which are accessing the variables.

Under http://svnmios.midibox.org/listing.php?repname=svn.mios&path=%2Ftrunk%2Fmodules%2F you will find several programming examples, e.g. http://svnmios.midibox.org/filedetails.php?repname=svn.mios&path=%2Ftrunk%2Fmodules%2Fblm%2Fblm.inc (search for BANKED)

Best Regards, Thorsten.

Link to comment
Share on other sites

OK, then that was it. However, I did it in C now, does not really slow down anything..... Still learning... :)

At least now i get a smooth interpolation between 0 and 32 steps (which is 33 steps in total).

Best, ALEXander..

/////////////////////////////////////////////////////////////////////////////
// Interpolate
/////////////////////////////////////////////////////////////////////////////
unsigned char KNOEPFLI_Interpolate32(unsigned char step, unsigned char value1, unsigned char value2)
{
	unsigned char swap, diff;

	//send out value2 if step is the max value
	if( step == 32 ) {
		return value2;
	};
	//send out value1 if step i 0
	if( step == 0 ) {
		return value1;
	};
	//invert the interpolation if value1 > value2
	if( value1 > value2 ) {
		//swap the values
		swap = value2;
		value2 = value1;
		value1 = swap;
		//--step because we are counting from 0 to 32, not to 31
		--step;
		//invert the step counter
		step = ~step;
		//clear the upper three bits
		step &= 0x1f;
	};

	//get the difference
	diff = value2 - value1;

	//divide it through the total number of steps (>>5) and multiply it with step (gives an integer) then get the high byte, 

	//shift the step counter three to the left to make it 8bit, store it in PRODL
	PRODL = step << 3;

	//store diff in PRODH
	PRODH = diff;  

	//do the multiplication in assembler
	__asm
    movf _PRODL, W
    mulwf _PRODH, 0
	__endasm;

	//add the lower value
	return value1 + PRODH;

}

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...