Jump to content

Speed up MIOS


wackazong
 Share

Recommended Posts

Hi!

Is it possible to achieve substantial speed improvements in MIOS when disabling some parts of it? And how is it done?

I need only DIN and IIC and MIDI, nothing else regarding input/output, not DOUT, no AIN, no LCD even.

Would it be worth disabling these? I think they could just be taken out of the mainloop, or disabled in the mios_config file?

Thanks, ALEXander.

Link to comment
Share on other sites

Hi,

There are several options to optimize your application:

- think about more effective code & functionality

- don't use divisions & multiplications

- don't use the sdcc library

- optimize your code in ASM

- write the whole application in ASM

of course there are also a million programming books out there discussing optimization strategies (and I'm sure there will be reasonable disapprove of my suggestions above ;-) )

Of course there's always the possibility to write your own program in ASM without MIOS at all. I guess this would be easier than ripping apart MIOS (though you can surely try, the sources are available - though I really don't see the advantage in gaining 1 µS by loosing or breaking up an extremely reliable and tested system layer).

The new programming environment already enables the in-/exclusion of rarely used libs like AOUT.

The whole operating system has been written in assembly language and have been optimized for speed. MIOS currently allocates 8k of program memory (additional 4k are reserved for future extensions) and 640 bytes of RAM. The system architecture is quite stable' date=' additional functions which load the CPU are not planned. The SRIO handler requires just only 75 uS to fetch the data from 128 digital input pins and to write out data to 128 digital output pins. 16 rotary encoders are handled within 100 uS. Analog inputs are scanned in background, every 200 uS a conversion result is available, on changes outside a definable deathband a user hook will be triggered. Up to 256 MIDI events can trigger dedicated functions, the processing of the event list requires about 300 uS. MIDI events can also be processed by a user routine for sysex parsing or similar jobs. A user timer allows to realize time triggered code, best example is the MIDIbox SID adaptation which runs 1:1 cycle accurate to the PIC16F version (but one cycle is processed 3 times faster than on the PIC16F). Several measures have been taken to allow a unified interaction with MIOS: all MIOS runtime variables have been located to the BANKED RAM area and don't allocate the ACCESS page. Input and output parameters of functions and hooks are transferred over WREG, three additional registers (MIOS_PARAMETER[123']) and the FSR1 pointer. TBLPTR[LH], TABLAT, PROD[LH], FSR0 and FSR2 are saved and restored if a MIOS function temporary gets use of these SFRs.

so regarding the fact that you are referring to this:

The one which just uses Tick works beautifully, and the core stays responsive, while the other one does not work at all, only when I increase the second paramer of the init to 100. But also then the function is awfully slow. The core is also responsive then, but the function does not work as expected.

if you are experiencing delays or recognizable timing issues, it's definitely more an issue with your custom software (or hardware - or a general construction flaw).

My ACSensorizer is filled with code up to the last byte, does timing and beat calculations, reads permanently it's 8 AIN-ports and processes quite a few calculations (incl. divisions to scale and smooth values), all in C - and I never ever recognized anything giving me the impression it would not be realtime.

regards,

ac

Link to comment
Share on other sites

Yeah, I believed so. Nevertheless, when I am constantly fading 128 RGB-LEDs from one color to another, the system does slow down :-) But: The speed is just about ok, I do not want to use the new ARM system yet :)

I think I coded more or less efficiently, the things I do are very simple, therefore I think that assembler optimisation is rarely needed. I do a lot of IIC communication, there is a delay in these assembler functions, maybe that consumes a lot of processor time?

Anyway, I just wanted to know whether there is an easy way to disable non-neede functions of MIOS in order to speed it up. Am I right that the place to look is the MIOS_config.h file, or is there more?

Thanks!

ALEXander.

Link to comment
Share on other sites

You're kinda in the right place. It is possible to recmpile a customised version of mios which excludes some drivers. TK was kind enough to add this feature at the request of a couple of performance hungry devs (yep I was one) so that we can compile a smaller version of MIOS. It won't make it faster though. You might save a few instructions at best.

Yes, IIC transfers can cause delays, but coding the right way can get around that in most cases.

AC is right - optimise. Post your code and I'm sure we can find a a few things to soup up.

Link to comment
Share on other sites

Oh, whatever, I will post it here.

What I do is: I have 127 RGB LEDs connected via driver chips to the core. The communication is via IIC. Also, for each LED, there is a button. The LEDs can be set to a color, but they can also go into BLINK modus. In BLINK modus, they fade between two colors in 32 steps in a regular interval. Additionally, when the corresponding button is pressed, the LED FLASHES up in a third color, which is then faded into the normal color in a second or so. Blinking and Flashing can occur at the same time, without disturbing the blinking frequency or phase.

These are the variables I am using. Lots of unsigned char arrays, but no problems with variable memory so far.

/////////////////////////////////////////////////////////////////////////////
// Global variables
/////////////////////////////////////////////////////////////////////////////

//status register for all leds
knoepfli_led_status_t knoepfli_led_status[KNOEPFLI_LED_NUMBER];

//timer counter through all leds
unsigned char knoepfli_led_counter;

//color state arrays for all LEDs. Three separate arrays for the colors because of array size limitations on the pic
/////////////////////////////////////////////////////////////////////////////
//this array contains the current color of the LEDs, without the flash effect but with blinking
unsigned char knoepfli_led_color_now_red[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_now_green[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_now_blue[KNOEPFLI_LED_NUMBER];

//blink stuff
/////////////////////////////////////////////////////////////////////////////
//these arrays contain one of the two blinking colors for all LEDs
unsigned char knoepfli_led_color_from_red[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_from_green[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_from_blue[KNOEPFLI_LED_NUMBER];

//these arrays contain the second color for the blinking
unsigned char knoepfli_led_color_to_red[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_to_green[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_to_blue[KNOEPFLI_LED_NUMBER];

//this array contains the step counter for the blinking
unsigned char knoepfli_led_blink_counter[KNOEPFLI_LED_NUMBER];
//this array contains the direction of the step counter
//only one bit per LED is needed, but bitfields with a size of 128 do not seem to work
unsigned char knoepfli_led_blink_direction[KNOEPFLI_LED_NUMBER];

//flash stuff
/////////////////////////////////////////////////////////////////////////////
//these arrays contain the flash color of all LEDs
unsigned char knoepfli_led_color_flash_red[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_flash_green[KNOEPFLI_LED_NUMBER];
unsigned char knoepfli_led_color_flash_blue[KNOEPFLI_LED_NUMBER];
//this array contains the step counter for all LEDs for the flash
unsigned char knoepfli_led_flash_counter[KNOEPFLI_LED_NUMBER];
The next function is called periodically by Tick in the main loop. This could be improved by setting a flag in Timer and checking the flag in Tick to get regular intervals
/////////////////////////////////////////////////////////////////////////////
// Blink and Flash Handler
// Treats only one LED per call
// First determines the current color of the LED, if it is blinking
// Then additionally applies the flash color fade, if the LED is flashing
/////////////////////////////////////////////////////////////////////////////
void KNOEPFLI_Blink_and_Flash_Handler()
{
	unsigned char red,green,blue,change;

//	//avoid the compiler warnings about non-defined variables
//	red = 0;
//	green = 0;
//	blue = 0;

	//set change flag to false
	change = 0;

	if( knoepfli_led_status[knoepfli_led_counter].BLINK == 1 ) {

		//the color has to be changed, set the flag
		change = 1;

		red = KNOEPFLI_Interpolate32( knoepfli_led_blink_counter[knoepfli_led_counter], knoepfli_led_color_from_red[knoepfli_led_counter], knoepfli_led_color_to_red[knoepfli_led_counter]);
		green = KNOEPFLI_Interpolate32( knoepfli_led_blink_counter[knoepfli_led_counter], knoepfli_led_color_from_green[knoepfli_led_counter], knoepfli_led_color_to_green[knoepfli_led_counter]);
		blue = KNOEPFLI_Interpolate32( knoepfli_led_blink_counter[knoepfli_led_counter], knoepfli_led_color_from_blue[knoepfli_led_counter], knoepfli_led_color_to_blue[knoepfli_led_counter]);		

		knoepfli_led_color_now_red[knoepfli_led_counter] = red;
		knoepfli_led_color_now_green[knoepfli_led_counter] = green;
		knoepfli_led_color_now_blue[knoepfli_led_counter] = blue;

		if( knoepfli_led_blink_direction[knoepfli_led_counter] == 0 ) {
			if( knoepfli_led_blink_counter[knoepfli_led_counter] == 32) {
				knoepfli_led_blink_direction[knoepfli_led_counter] = 1;
				--knoepfli_led_blink_counter[knoepfli_led_counter];
			} else {
				++knoepfli_led_blink_counter[knoepfli_led_counter];
			};
		} else { 
			if( knoepfli_led_blink_counter[knoepfli_led_counter] == 0) {
				knoepfli_led_blink_direction[knoepfli_led_counter] = 0;
				++knoepfli_led_blink_counter[knoepfli_led_counter];
			} else {
				--knoepfli_led_blink_counter[knoepfli_led_counter];
			};
		};
	};

	if( knoepfli_led_status[knoepfli_led_counter].FLASH == 1 ) {

		//the color has to be changed, set the flag
		change = 1;

		red = KNOEPFLI_Interpolate32( knoepfli_led_flash_counter[knoepfli_led_counter], knoepfli_led_color_now_red[knoepfli_led_counter], knoepfli_led_color_flash_red[knoepfli_led_counter]);
		green = KNOEPFLI_Interpolate32( knoepfli_led_flash_counter[knoepfli_led_counter], knoepfli_led_color_now_green[knoepfli_led_counter], knoepfli_led_color_flash_green[knoepfli_led_counter]);
		blue = KNOEPFLI_Interpolate32( knoepfli_led_flash_counter[knoepfli_led_counter], knoepfli_led_color_now_blue[knoepfli_led_counter], knoepfli_led_color_flash_blue[knoepfli_led_counter]);

		if( knoepfli_led_flash_counter[knoepfli_led_counter] == 0 ) {
			knoepfli_led_status[knoepfli_led_counter].FLASH = 0;
		} else {
			--knoepfli_led_flash_counter[knoepfli_led_counter];
		};
	};

	if( change == 1) {
		//Send Brightness red
		MIOS_IIC_Start();    // start IIC
		MIOS_IIC_ByteSend( knoepfli_led_address_red[knoepfli_led_counter].DRIVER ); // send device address, bit #0 cleared to notify a write!!!
		MIOS_IIC_ByteSend( 0x02 + knoepfli_led_address_red[knoepfli_led_counter].LED );  // select brightness register of the corresponding led, the first one is 0xa2, no autoincrement
		MIOS_IIC_ByteSend( red );  // send brightness
		MIOS_IIC_Stop();

		//Send Brightness green
		MIOS_IIC_Start();    // start IIC
		MIOS_IIC_ByteSend( knoepfli_led_address_green[knoepfli_led_counter].DRIVER ); // send device address, bit #0 cleared to notify a write!!!
		MIOS_IIC_ByteSend( 0x02 + knoepfli_led_address_green[knoepfli_led_counter].LED );  // select brightness register of the corresponding led, the first one is 0xa2, no autoincrement
		MIOS_IIC_ByteSend( green );  // send brightness
		MIOS_IIC_Stop();

		//Send Brightness blue
		MIOS_IIC_Start();    // start IIC
		MIOS_IIC_ByteSend( knoepfli_led_address_blue[knoepfli_led_counter].DRIVER ); // send device address, bit #0 cleared to notify a write!!!
		MIOS_IIC_ByteSend( 0x02 + knoepfli_led_address_blue[knoepfli_led_counter].LED );  // select brightness register of the corresponding led, the first one is 0xa2, no autoincrement
		MIOS_IIC_ByteSend( blue );  // send brightness
		MIOS_IIC_Stop();

	};

	//increase the counter for the next run of the routine
	++knoepfli_led_counter;

	if( knoepfli_led_counter == KNOEPFLI_LED_NUMBER ) {
		knoepfli_led_counter = 0;
	};

}
And this is the interpolation function, now coded in C. Assembler did not work properly, and I decided to try it in C. Maybe this leaves some room for improvement.
/////////////////////////////////////////////////////////////////////////////
// Interpolate32
// Gives back an interpolated value between value1 and value2
// The total number of steps is 33, from 0 to 32
/////////////////////////////////////////////////////////////////////////////
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;

}

Well, what do you think? Any questions will of course be answered most gladly :)

ALEXander.

Link to comment
Share on other sites

Err... if I'm gonna optimise it, I kinda need to compile it.... Can I have the rest?

One tip: Array accesses are sloowwwwwwwww, and this thing is one array access after the other.

Don't worry too much about the .list file. Check out output/main.asm to see what a mess your tidy C code becomes...

Link to comment
Share on other sites

Yeah, thats all arrays, because I have to go through the 127 LEDs, with each three colors.

Anyway, I did not expect that you really wanted to dwelve that deep into my code, but that is  of course more than welcome.

All files are attached, the makefile contains the path definitions at the top, after adjusting them it should compile normally.

Thanks and best, ALEXander.

knoepfli.zip

knoepfli.zip

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...
 Share

×
×
  • Create New...