ON 20081016@10:11:58 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/index.htm#39737.4249652778 Isaac Marino Bavaresco[IMB-yahoo-J86] Code: /techref/member/IMB-yahoo-J86/hi-techmemcpy.htm




ON 20081016@10:21:28 AM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/hi-techmemcpy.htm#
James Newton[JMN-EFP-786] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\hi-techmemcpy.htm&version=0



ON 20081016@12:47:03 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/hi-techmemcpy.htm#39737.5326736111
Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This routine is a substitution for the one in the Hi-Tech PICC compiler library.

The original has some limitations that I wanted to overcome:
1 - The data destination must always be in bank 0 or bank 1.
2 - If the data source is in program memory (retlw table) it must be 256 entries long or less, and it must not cross a 256 instruction address boundary.

My version can copy data to any RAM bank, from any RAM bank or a retlw table, without any size or alignment restriction. Besides, it is over twice as fast as the original.

There are draw-backs tough:
1 - The parameter 'Dst' is declared 'const void *', when it should be declared 'void *', but a non-const pointer can point only to banks 0 and 1 or to banks 2 and 3, never to all banks. It's no problem if the programmer is a bit careful.
2 - the function returns 'void', where it should return 'void *'. I did this to save some RAM and execution time (I personally never used the return from memcpy, as it is the same destination pointer I already have). If one needs it the right way, it is easy to fix.

Note:
If a pointer to program memory is passed to 'Dst', the function returns without doing nothing.

;==============================================================================
; Copyright (c) 2008, Isaac Marino Bavaresco
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;     * Redistributions of source code must retain the above copyright
;       notice, this list of conditions and the following disclaimer.
;     * Neither the name of the author nor the
;       names of its contributors may be used to endorse or promote products
;       derived from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;==============================================================================
; isaacbavaresco@yahoo.com.br
;==============================================================================
INDF		equ	0
PCL		equ	2
STATUS		equ	3
FSR		equ	4
PCLATH		equ	10
;===============================================================================
_memcpy$Dst	set	?_memcpy+0
_memcpy$DstBnk	set	?_memcpy+1
_memcpy$Src	set	?_memcpy+2
_memcpy$SrcBnk	set	?_memcpy+3
_memcpy$Len	set	?_memcpy+4
;===============================================================================
; void memcpy( const void *Dst, const void *Src, unsigned char Len )

		psect	text0,local,class=CODE,delta=2

		global	_memcpy
		signat	_memcpy,0x3078
		fnsize	_memcpy,0,5
		global	?_memcpy

_memcpy:	clrf	STATUS
		;---------------------------------------------------------------
		btfss	_memcpy$DstBnk,7	; if( !( Dst & 0x8000 ))
DstInROM:	return				;    return;

		incf	_memcpy$Len,f
		;---------------------------------------------------------------
DstInRAM:	btfsc	_memcpy$SrcBnk,7	; if( Src & 0x8000 )
		goto	SrcInRAMTest
		;---------------------------------------------------------------
SrcInROM:	btfsc	_memcpy$DstBnk,0
		bsf	STATUS,7
		movf	_memcpy$Dst,w
		movwf	FSR
		
		goto	SrcInROMTest
		;---------------------------------------------------------------
SrcInROMLoop:	call	LookUp

		movwf	INDF

		pagesel	$

		incfsz	_memcpy$Src,f
		goto	$+2
		incf	_memcpy$SrcBnk,f

		incf	FSR,f

SrcInROMTest:	decfsz	_memcpy$Len,f
		goto	SrcInROMLoop
		return
		;---------------------------------------------------------------
LookUp:		movf	_memcpy$SrcBnk,w
		movwf	PCLATH
		movf	_memcpy$Src,w
		movwf	PCL
		;---------------------------------------------------------------
SrcInRAM:	bcf	STATUS,7
		btfsc	_memcpy$SrcBnk,0
		bsf	STATUS,7
		movf	_memcpy$Src,w
		movwf	FSR

		movf	INDF,w
		movwf	btemp+0

		bcf	STATUS,7
		btfsc	_memcpy$DstBnk,0
		bsf	STATUS,7
		movf	_memcpy$Dst,w
		movwf	FSR

		movf	btemp+0,w
		movwf	INDF

		incf	_memcpy$Src,f
		incf	_memcpy$Dst,f

SrcInRAMTest:	decfsz	_memcpy$Len,f
		goto	SrcInRAM
		return
;===============================================================================
		psect	temp,ovrld,class=BANK0,space=1
btemp		ds	1
;===============================================================================
ON 20081017@8:25:33 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/index.htm#39738.8510532407 Isaac Marino Bavaresco[IMB-yahoo-J86] Code: /techref/member/IMB-yahoo-J86/heap-mgmt.htm
Heap management for PICS, mostly PIC18 and FreeRTOS (www.freertos.org)
ON 20081017@8:28:53 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8533796296 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This if file "malloc.c". Works with Microchip MPLAB-C18, Hi-Tech PICC and Hi-Tech PICC-18.

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#if			defined __18CXX	// PIC18 family with Microchip MPLAB-C18 compiler

	#include 
	#define	INT_MASK 0xc0

#elif		defined _PIC14	// PIC16 family with Hi-Tech PICC compiler

	#include 
	#define	INT_MASK 0x80

#elif		defined _PIC18	// PIC18 family with Hi-Tech PICC-18 compiler

	#include 
	#define	INT_MASK 0xc0

#else	//	defined _PIC18
	#error "Architecture not supported!"
#endif	//	defined __18CXX
//==============================================================================
#include 
#include 
#include 
//==============================================================================
#if			USING_FREE_RTOS == 1

void		vTaskSuspendAll			( void );
signed char	xTaskResumeAll			( void );
#define		DISABLE_INTERRUPTS()	vTaskSuspendAll()
#define		RESTORE_INTERRUPTS()	xTaskResumeAll()

#else	//	USING_FREE_RTOS == 1

#define		DISABLE_INTERRUPTS()	{Aux = INTCON & INT_MASK; INTCON &= ~INT_MASK;}
#define		RESTORE_INTERRUPTS()	{INTCON |= Aux;}

#endif	//	USING_FREE_RTOS == 1
//==============================================================================
void RAM *malloc( S_CLASS sizeram_t Length )
	{
	struct _AllocBlock RAM *p, *q;
#if			USING_FREE_RTOS != 1
	unsigned char Aux;
#endif	//	USING_FREE_RTOS != 1

	// We will not allocate 0 bytes.
	if( Length == 0 )
		// The allocation failed.
		return NULL;
	
//	// The length should always be even. (Not for 14 or 16 bit (program word) PICs).
//	Length = ( Length + 1 ) & -2;

#if			defined __18CXX || defined _PIC18
	// The length should be at least 2. (Not for 14 bit (program word) PICs)
	if( Length < sizeof __freelist.Next )
		Length = sizeof __freelist.Next;
#endif	//	defined __18CXX || defined _PIC18

	DISABLE_INTERRUPTS();

	// Then we iterate through the free list to find a suitable block.
	for( p = __freelist.Next, q = &__freelist; p != NULL && p->Length < Length; q = p, p = p->Next )
		;	// Empty statement

	// If p is NULL is because there is no suitable block.
	if( p == NULL )
		{
		RESTORE_INTERRUPTS();
		// The allocation failed.
		return NULL;
		}

	// If the block length is not enough to be splitted, we allocate the whole block.
	if( p->Length < Length + sizeof( struct _AllocBlock ))
		{
		// Remove the block from the free list.
		q->Next = p->Next;
		}
	// We have to split the block.
	else
		{
		// Make q point to the begining of the new block.
		q = (struct _AllocBlock RAM *)( (unsigned char RAM *)p + p->Length - Length );
		// Reduce the original block length.
		p->Length -= Length + sizeof __freelist.Length;
		// Set the new block length.
		p = q;
		p->Length = Length;
		}

	RESTORE_INTERRUPTS();

	// Return the address of the data area of the block.
	return (unsigned char RAM *)p + sizeof __freelist.Length;
	}
//==============================================================================
ON 20081017@8:30:02 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8541782407 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This if file "free.c". Works with Microchip MPLAB-C18, Hi-Tech PICC and Hi-Tech PICC-18.

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#if			defined __18CXX	// PIC18 family with Microchip MPLAB-C18 compiler

	#include 
	#define	INT_MASK 0xc0

#elif		defined _PIC14	// PIC16 family with Hi-Tech PICC compiler

	#include 
	#define	INT_MASK 0x80

#elif		defined _PIC18	// PIC18 family with Hi-Tech PICC-18 compiler

	#include 
	#define	INT_MASK 0xc0

#else	//	defined _PIC18
	#error "Architecture not supported!"
#endif	//	defined __18CXX
//==============================================================================
#include 
#include 
#include 
//==============================================================================
#if			USING_FREE_RTOS == 1

void		vTaskSuspendAll			( void );
signed char	xTaskResumeAll			( void );
#define		DISABLE_INTERRUPTS()	vTaskSuspendAll()
#define		RESTORE_INTERRUPTS()	xTaskResumeAll()

#else	//	USING_FREE_RTOS == 1

#define		DISABLE_INTERRUPTS()	{Aux = INTCON & INT_MASK; INTCON &= ~INT_MASK;}
#define		RESTORE_INTERRUPTS()	{INTCON |= Aux;}

#endif	//	USING_FREE_RTOS == 1
//==============================================================================
void free( S_CLASS void RAM *r )
	{
	struct _AllocBlock RAM *p, *q;
#if			USING_FREE_RTOS != 1
	unsigned char Aux;
#endif	//	USING_FREE_RTOS != 1

	// We will not free a NULL pointer
	if( r == NULL )
		// Finished
		return;

	// Make 'r' point to the true begining of the allocated block
	r = (unsigned char RAM *)r - sizeof __freelist.Length;

	DISABLE_INTERRUPTS();

	// Then we iterate through the free list to find the point where the block will be inserted
	for( p = __freelist.Next, q = &__freelist; p != NULL && p < (struct _AllocBlock RAM *)r; q = p, p = p->Next )
		;	// Empty statement

	// Make the block point to its successor in the free list
	(( struct _AllocBlock RAM *)r)->Next	= p;
	// Make the predecessor block point to the block being freed
	q->Next								= r;

	// If the block is contiguous to its successor, then we merge them
	if( (ptrdiffram_t)r + ((struct _AllocBlock RAM *)r)->Length + sizeof __freelist.Length == (ptrdiffram_t)p )
		{
		// Make the block point to the successor of its successor
		((struct _AllocBlock RAM *)r)->Next		 = p->Next;
		// Extend the block to the end of its successor
		((struct _AllocBlock RAM *)r)->Length	+= p->Length + sizeof __freelist.Length;
		}

	// If the predecessor block is contiguous to this block, then we merge them
	if( (ptrdiffram_t)q + ((struct _AllocBlock RAM *)q)->Length + sizeof __freelist.Length == (ptrdiffram_t)r )
		{
		// Make the predecessor block point to the current block's successor
		((struct _AllocBlock RAM *)q)->Next		 = ((struct _AllocBlock RAM *)r)->Next;
		// Extend the predecessor block to the end of the current block
		((struct _AllocBlock RAM *)q)->Length	+= ((struct _AllocBlock RAM *)r)->Length + sizeof __freelist.Length;
		}

	RESTORE_INTERRUPTS();
	}
//==============================================================================
ON 20081017@8:36:31 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\heap-mgmt.htm&version=2 ON 20081017@8:38:49 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8602777778 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This file is "freelist.c".

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#include 
//==============================================================================
// Head of the free blocks list in the heap.

struct _AllocBlock RAM __freelist;
//==============================================================================
ON 20081017@8:42:08 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8625925926 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This file is "__heap.c".

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#include 
//==============================================================================
#if			defined	__18CXX	// PIC18 family with Microchip MPLAB-C18 compiler

// For using more than 256 bytes, the linker-script must be changed.
unsigned char	RAM		__heap[256];

#elif		defined	_PIC14	// PIC16 family with Hi-Tech PICC compiler

// Works for PIC16F876A and PIC16F877A, using all of bank2 and bank3 (this is the
// maximum one can get from a PIC16).
// Please note that with these definitions, the heap is composed of two non-
// contiguous areas.
// For other PIC16 uC, change the definitions.
unsigned char	RAM		__heap[94];
unsigned char	bank3	__heap2[96];

#elif		defined	_PIC18	// PIC18 family with Hi-Tech PICC-18 compiler

// Hi-Tech PICC-18 is smart, you may use almost all of the RAM memory.
unsigned char	RAM		__heap[3000];

#else	//	defined	_PIC18
	#error "Architecture not supported!"
#endif	//	defined	__18CXX
//==============================================================================
void heapinit( void )
	{
#if			defined __18CXX || defined _PIC18

	((struct _AllocBlock RAM *)__heap)->Length	= sizeof __heap - sizeof __freelist.Length;
	((struct _AllocBlock RAM *)__heap)->Next	= NULL;

#elif		defined _PIC14

	__heap[0]	= sizeof __heap - sizeof __freelist.Length;
	__heap[1]	= (sizeram_t)__heap2;
	__heap2[0]	= sizeof __heap2 - sizeof __freelist.Length;
	__heap2[1]	= NULL;

#endif	//	defined _PIC14

	__freelist.Length		= 0;
	__freelist.Next			= (struct _AllocBlock RAM *)__heap;
	}
//==============================================================================
ON 20081017@8:44:48 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\heap-mgmt.htm&version=5 ON 20081017@8:48:04 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.866712963 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This file is "__reclaim_stack.c". Useful only when used with PIC18 and FreeRTOS (www.freertos.org).

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#include 
//==============================================================================

// Annex the original system stack to the heap.
//
// Should be called only once, inside a thread, after the call to the functions
// heapinit() and vTaskStartScheduler(), when the original stack is no more in use.
//
// This function works only for the combination PIC18 microcontrollers +
// MPLAB-C18 compiler + FreeRTOS (www.freertos.org).

// TIP: If you make a careful linker-script, you may join the stack to the heap
// as one contiguous block, thus optimizing the available memory.
// Define the stack just before the heap, with nothing between them. 
// When you call '__reclaim_stack', it calls 'free' passing the stack as a block
// to free, and because 'malloc' allocates from the end of the heap, the beginning
// of the heap contains free memory, and 'free' joins the stack to this free memory.

//         before                            after         
//                                                          
// |                     |           |                     |
// +---------------------+           +---------------------+
// |                     |           |                     |   lower
// |        stack        |           |                     | addresses
// |                     |           |                     |
// +---------------------+           |      free heap      |
// |                     |           |                     |
// |      free heap      |           |                     |
// |                     |           |                     |
// + - - - - - - - - - - +           + - - - - - - - - - - +
// |                     |           |                     |
// |      used heap      |           |      used heap      |  higher
// |                     |           |                     | addresses
// +---------------------+           +---------------------+
// |                     |           |                     |


// The standard library implementation of __reclaim_stack() do nothing.
// The user should implement it, because there is no way to know the stack size
// at run time or when building the library.

/******************************************************************************
 * Just uncomment the #define and the two lines inside the function.		  *
 * Don't forget to set the macro STACK_SIZE to the correct value.			  *
 ******************************************************************************/

// Be careful, this definition should agree with the linker-script
//#define STACK_SIZE		0x100

void __reclaim_stack( void )
	{
	//((struct _AllocBlock RAM *)&_stack)->Length	= STACK_SIZE - sizeof( sizeram_t );
	//free( &((struct _AllocBlock RAM *)&_stack)->Next );
	}
//==============================================================================
ON 20081017@8:50:49 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8686226852 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This is file "alloc.h".

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#ifndef		__ALLOC_H__
#define		__ALLOC_H__
//==============================================================================
#include 

#if			defined __18CXX	// PIC18 family with Microchip MPLAB-C18 compiler

#define	RAM		far ram
#define	S_CLASS	auto

#elif		defined _PIC14	// PIC16 family with Hi-Tech PICC compiler

#define	RAM		 bank2
#define	S_CLASS
typedef unsigned char sizeram_t;
typedef unsigned char ptrdiffram_t;

#elif		defined _PIC18	// PIC18 family with Hi-Tech PICC-18 compiler

#define	RAM
#define	S_CLASS
typedef unsigned short sizeram_t;
typedef unsigned short ptrdiffram_t;

#else	//	defined _PIC18

#error "Architecture not supported!"

#endif	//	defined __18CXX
/*=========================================================================*//**
\brief Initializes the heap.

Must be called before any call to other functions that use the heap.
*//*==========================================================================*/
void		heapinit( void );

/*=========================================================================*//**
\brief Allocates a block of RAM memory in the heap.

\param len Length of the block in bytes.

\return In case of success returns a pointer to the allocated block,
in case of failure, returns ::NULL.
*//*==========================================================================*/
void RAM *malloc( S_CLASS sizeram_t len );

/*=========================================================================*//**
\brief Frees a block of RAM memory previously allocated by the function ::malloc.

\param r Pointer to the block to free.
*//*==========================================================================*/
void		free( S_CLASS void RAM *r );

//##############################################################################
#if			defined __18CXX
//##############################################################################

/*=========================================================================*//**
\brief Annex the original system stack to the heap.

Should be called only once, inside a thread, after the call to the functions
heapinit() and vTaskStartScheduler(), when the original stack is no more in use.

This function works only for the combination PIC18 microcontrollers +
MPLAB-C18 compiler + FreeRTOS (www.freertos.org).
*//*==========================================================================*/
void		__reclaim_stack( void );

//##############################################################################
#endif	//	defined __18CXX
//##############################################################################

//==============================================================================
#endif	//	__ALLOC_H__
//==============================================================================
ON 20081017@8:52:22 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8696875 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This is file "heap.h".

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
#ifndef		__HEAP_H__
#define		__HEAP_H__
//==============================================================================
#include 
/*=========================================================================*//**
\brief Control structure for controlling the free blocks list in the heap.
*//*==========================================================================*/
typedef struct _AllocBlock
	{
	/// Length of the block.
	sizeram_t				Length;
	/// Pointer to the next free block.
	struct _AllocBlock RAM	*Next;
	} AllocBlock;

/*=========================================================================*//**
\brief Head of the free blocks list in the heap.
*//*==========================================================================*/
extern struct _AllocBlock RAM __freelist;

//==============================================================================
#endif	//	__HEAP_H__
//==============================================================================
ON 20081017@8:53:57 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.870787037 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This is file "main.c". Useful for demonstration purpose only.

//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
/*
	This file is just an example of how to use "Heap Management For Small
	Microcontrollers".
*/
//==============================================================================
#include 
//==============================================================================
char RAM *v[64];
void main( void )
	{
	char i;
	char RAM *p, *q, *r;

	heapinit();

	while( 1 )
		{
		for( i = 0; i < sizeof v / sizeof v[0]; i++ )
			v[i] = malloc( 20 );
	
		p = malloc( 93 );
		q = malloc( 93 );
		r = malloc( 1 );
	
		for( i = 0; i < sizeof v / sizeof v[0]; i += 2 )
			free( v[i] );
	
		for( i = 1; i < sizeof v / sizeof v[0]; i += 2 )
			free( v[i] );
	
		free( q );
		free( p );
		free( r );
		}

	}
//==============================================================================
void		vTaskSuspendAll( void )
	{
	}
//==============================================================================
signed char	xTaskResumeAll( void )
	{
	return 0;
	}
//==============================================================================
ON 20081017@8:57:45 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8734375 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This is file "UsingFreeRTOS.h".

#if	0
//==============================================================================
// This file is part of "Heap Management For Small Microcontrollers".
// v1.03 (2008-10-17)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
//
// This file is included from both ".c" files and ".asm" files.
//
//==============================================================================
#endif

#define USING_FREE_RTOS	0
ON 20081017@9:02:02 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.876412037 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This is file "malloc.asm", it is an optional substitution for the file "malloc.c". It is much more optimized, but works only for PIC18 with Microchip MPLAB-C18.

;===============================================================================
; This file is part of "Heap Management For Small Microcontrollers".
; v1.03 (2008-10-17)
; isaacbavaresco@yahoo.com.br
;===============================================================================
; Copyright (c) 2007-2008, Isaac Marino Bavaresco
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;     * Redistributions of source code must retain the above copyright
;       notice, this list of conditions and the following disclaimer.
;     * Neither the name of the author nor the
;       names of its contributors may be used to endorse or promote products
;       derived from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;===============================================================================
#include 
;===============================================================================
		radix	decimal
;===============================================================================
#include 
;===============================================================================
#if	  USING_FREE_RTOS == 1
;-------------------------------------------------------------------------------
		extern	vTaskSuspendAll
		extern	xTaskResumeAll
#define	LOCALS_SIZE	4
DISABLE_INTERRUPTS macro
		call	vTaskSuspendAll
		endm

RESTORE_INTERRUPTS macro
		call	xTaskResumeAll
		endm
;-------------------------------------------------------------------------------
#else	; USING_FREE_RTOS == 1
;-------------------------------------------------------------------------------
#define	LOCALS_SIZE	5
DISABLE_INTERRUPTS macro
;			Aux	 = INTCON & 0xc0;
		movlw	0xc0
		andwf	INTCON,w,ACCESS
		movwf	[Aux+0]
;			INTCON	&= 0x3f;
		movlw	0x3f
		andwf	INTCON,f,ACCESS
		endm

RESTORE_INTERRUPTS macro
;			INTCON	|= Aux;
		movf	[Aux+0],w
		iorwf	INTCON,f,ACCESS
		endm
;-------------------------------------------------------------------------------
#endif	; USING_FREE_RTOS == 1
;===============================================================================
ALLOC		code
;===============================================================================
#define Length	0
#define	p	4
#define q	6
#define	Aux	8

		extern	__freelist
		extern	vTaskSuspendAll
		extern	xTaskResumeAll
;===============================================================================
		global	malloc
;		void ram *malloc( sizeram_t Length )

malloc:		movff	FSR2L,POSTINC1
		movff	FSR2H,POSTINC1
		movff	FSR1L,FSR2L
		movff	FSR1H,FSR2H

		subfsr	2,4

;			{
;			struct _AllocBlock ram	*p,*q;
;		#if		USING_FREE_RTOS != 1
;			unsigned char Aux;
;		#endif	//	USING_FREE_RTOS != 1

		addfsr	1,LOCALS_SIZE

;			// We will not allocate 0 bytes.
;			if( Length == 0 )
		movf	[Length+0],w
		iorwf	[Length+1],w
		bnz	NotZero
;				// The allocation failed.
;				return NULL;
		clrf	PRODL,ACCESS
		clrf	PRODH,ACCESS
		bra	Ret

NotZero:	
;		//	// The length should always be even. (Not for 14 or 16 bit (program word) PICs).
;		//	Length = ( Length + 1 ) & -2;
;
;		infsnz	[Length+0],f
;		incf	[Length+1],f
;		bcf	[Length+0],0

;		#if		defined __18CXX || defined _PIC18
;			// The length should be at least 2. (Not for 14 bit (program word) PICs)
;			if( Length < sizeof __freelist.Next )
;				Length = sizeof __freelist.Next;
;		#endif	//	defined __18CXX || defined _PIC18

		movlw	2
		subwf	[Length+0],w
		movlw	0
		subwfb	[Length+1],w
		bc	TwoOrMore

		movlw	2
		movwf	[Length+0]

TwoOrMore:

;			DISABLE_INTERRUPTS();
		DISABLE_INTERRUPTS

;			// Then we iterate trough the free list to find a suitable block.
;			for( q = &__freelist,p = __freelist.Next; p != NULL && p->Length < Length; q = p, p = p->Next )
;				;	// Empty statement
 
		movlw	low __freelist		; for( q = &__freelist,
		movwf	[q+0]
		movlw	high __freelist
		movwf	[q+1]
 
		movff	__freelist+2,FSR0L	; p = __freelist.Next;
		movff	__freelist+3,FSR0H
 
Loop:		movf	FSR0L,w,ACCESS		; p != NULL
		iorwf	FSR0H,w,ACCESS
		bz	Fail

		movf	[Length+0],w		; && p->Length < Length;
		subwf	POSTINC0,w,ACCESS
		movf	[Length+1],w
		subwfb	POSTDEC0,w,ACCESS
		bc	Found

		movf	FSR0L,w,ACCESS		; q = p,
		movwf	[q+0]
		movf	FSR0H,w,ACCESS
		movwf	[q+1]

		addfsr	0,2			; p = p->Next );
		movf	POSTINC0,w,ACCESS
		movff	INDF0,FSR0H
		movwf	FSR0L,ACCESS

		bra	Loop

;			// If p is NULL is because there is no suitable block.
;			if( p == NULL )
;				{
;				RESTORE_INTERRUPTS();
;				// The allocation failed.
;				return NULL;
;				}

#if	  USING_FREE_RTOS == 1
Fail:		clrf	[p+0]
		clrf	[p+1]
#else	; USING_FREE_RTOS == 1
Fail:		clrf	PRODL,ACCESS
		clrf	PRODH,ACCESS
#endif	; USING_FREE_RTOS == 1
		bra	Epilog

;			// If the block length is not enough to be splitted, we allocate the whole block.
;			if( p->Length < Length + sizeof( struct _AllocBlock ))
;				{

Found:		movf	FSR0L,w
		movwf	[p+0]
		movf	FSR0H,w
		movwf	[p+1]

		movlw	0x04
		addwf	[Length+0],w
		movwf	PRODL,ACCESS
		movlw	0x00
		addwfc	[Length+1],w
		movwf	PRODH,ACCESS

		movf	PRODL,w,ACCESS
		subwf	POSTINC0,w,ACCESS
		movf	PRODH,w,ACCESS
		subwfb	POSTDEC0,w,ACCESS
		bc	SplitBlock

;				// Remove the block from the free list.
;				q->Next = p->Next;
 
AllocateWhole:	addfsr	0,2

		movff	POSTINC0,PRODL
		movff	POSTDEC0,PRODH
 
 		movsf	[q+0],FSR0L
		movsf	[q+1],FSR0H
		addfsr	0,2

		movff	PRODL,POSTINC0
		movff	PRODH,POSTDEC0

		bra	Finish
;				}
;			// We have to split the block.
;			else
;				{
;				// Make p point to the begining of the new block.
;				pTemp = (struct _AllocBlock ram *)( (unsigned char ram *)p + p->Length - Length );
SplitBlock:	movf	POSTINC0,w,ACCESS
		addwf	[p+0],f
		movf	POSTDEC0,w,ACCESS
		addwfc	[p+1],f

		movf	[Length+0],w
		subwf	[p+0],f
		movf	[Length+1],w
		subwfb	[p+1],f

;				// Reduce the original block length.
;				p->Length -= Length + sizeof __freelist.Length;

		movf	[Length+0],w
		subwf	POSTINC0,f,ACCESS
		movf	[Length+1],w
		subwfb	POSTDEC0,f,ACCESS

		movlw	0x02
		subwf	POSTINC0,f,ACCESS
		movlw	0x00
		subwfb	POSTDEC0,f,ACCESS


;				// Set the new block length.
;				p = pTemp;
		movsf	[p+0],FSR0L
		movsf	[p+1],FSR0H

;				p->Length = Length;
		movsf	[Length+0],POSTINC0
		movsf	[Length+1],POSTDEC0
		
;				}
;

;			RESTORE_INTERRUPTS();

;			// return the address of the data area of the block.
;			return (unsigned char RAM *)p + sizeof __freelist.Length;
 
;			}

#if	  USING_FREE_RTOS == 1
Finish:		movlw	0x02
		addwf	[p+0],f
		movlw	0x00
		addwfc	[p+1],f
Epilog:		RESTORE_INTERRUPTS
		movsf	[p+0],PRODL
		movsf	[p+1],PRODH
#else	; USING_FREE_RTOS == 1
Finish:		movlw	0x02
		addwf	[p+0],w
		movwf	PRODL,ACCESS
		movlw	0x00
		addwfc	[p+1],w
		movwf	PRODH,ACCESS
Epilog:		RESTORE_INTERRUPTS
#endif	; USING_FREE_RTOS == 1

Ret:		subfsr	1,LOCALS_SIZE + 1
		movff	POSTDEC1,FSR2H
		movff	INDF1,FSR2L
		return	0
;===============================================================================
		end
;===============================================================================
ON 20081017@9:03:05 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm#39738.8771296296 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

This is file "free.asm", it is an optional substitution for the file "free.c". It is much more optimized, but works only for PIC18 with Microchip MPLAB-C18.

;===============================================================================
; This file is part of "Heap Management For Small Microcontrollers".
; v1.03 (2008-10-17)
; isaacbavaresco@yahoo.com.br
;===============================================================================
; Copyright (c) 2007-2008, Isaac Marino Bavaresco
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
;     * Redistributions of source code must retain the above copyright
;       notice, this list of conditions and the following disclaimer.
;     * Neither the name of the author nor the
;       names of its contributors may be used to endorse or promote products
;       derived from this software without specific prior written permission.
;
; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;===============================================================================
#include 
;===============================================================================
		radix	decimal
;===============================================================================
#include 
;===============================================================================
#if	  USING_FREE_RTOS == 1
;-------------------------------------------------------------------------------
		extern	vTaskSuspendAll
		extern	xTaskResumeAll
#define	LOCALS_SIZE	6
DISABLE_INTERRUPTS macro
		call	vTaskSuspendAll
		endm

RESTORE_INTERRUPTS macro
		call	xTaskResumeAll
		endm
;-------------------------------------------------------------------------------
#else	; USING_FREE_RTOS == 1
;-------------------------------------------------------------------------------
#define	LOCALS_SIZE	7
DISABLE_INTERRUPTS macro
;			Aux	 = INTCON & 0xc0;
		movlw	0xc0
		andwf	INTCON,w,ACCESS
		movwf	[Aux+0]
;			INTCON	&= 0x3f;
		movlw	0x3f
		andwf	INTCON,f,ACCESS
		endm

RESTORE_INTERRUPTS macro
;			INTCON	|= Aux;
		movf	[Aux+0],w
		iorwf	INTCON,f,ACCESS
		endm
;-------------------------------------------------------------------------------
#endif	; USING_FREE_RTOS == 1
;===============================================================================
ALLOC		code
;===============================================================================
#define	r	0
#define	p	4
#define	q	6
#define Aux2	8
#define Aux	10

		extern	__freelist
;===============================================================================
		global	free
;15:		void free( void ram *r )

free:		movff	FSR2L, POSTINC1
		movff	FSR2H, POSTINC1
		movff	FSR1L,FSR2L
		movff	FSR1H,FSR2H

		subfsr	2,4

;16:			{
;17:			struct _AllocBlock ram	*p, *q;
;			unsigned short		Aux2;
;			unsigned char		Aux;

		addfsr	1,LOCALS_SIZE
;18:
;19:			if( r == NULL )

		movf	[r+0],w
		iorwf	[r+1],w
;20:				return;
		bnz	NotNULL
		bra	Finish
;21:		
;22:			r = (unsigned char *)r - 2;
NotNULL:	movlw	0x02
 		subwf	[r+0],f
		movlw	0
		subwfb	[r+1],f

		DISABLE_INTERRUPTS
;23:		
;24:			
;25:			for( p = __freelist.Next, q = &__freelist; p != NULL && p < (struct _AllocBlock ram *)r; q = p, p = p->Next )

		movlw	low __freelist
		movwf	[q+0]
		movlw	high __freelist
		movwf	[q+1]

		movff	__freelist+2,FSR0L	; p = __freelist.Next;
		movff	__freelist+3,FSR0H

Loop:		movf	FSR0L,w,ACCESS		; p != NULL
		iorwf	FSR0H,w,ACCESS
		bz	xa630

		movf	[r+0],w			; && p < (struct _AllocBlock ram *)r;
		subwf	FSR0L,w,ACCESS
		movf	[r+1],w
		subwfb	FSR0H,w,ACCESS
		bc	xa630

		movf	FSR0L,w,ACCESS		; q = p;
		movwf	[q+0]
		movf	FSR0H,w,ACCESS
		movwf	[q+1]

		addfsr	0,2			; p = p->Next );
		movf	POSTINC0,w,ACCESS
		movff	INDF0,FSR0H
		movwf	FSR0L,ACCESS

		bra	Loop
;26:				;	/* Empty statement */

xa630:		movf	FSR0L,w
		movwf	[p+0]
		movf	FSR0H,w
		movwf	[p+1]

;29:			q->Next					= r;
		movsf	[q+0],FSR0L
		movsf	[q+1],FSR0H
		addfsr	0,2
		movsf	[r+0],POSTINC0
		movsf	[r+1],POSTDEC0

;28:			((struct _AllocBlock ram *)r)->Next	= p;
		movsf	[r+0],FSR0L
		movsf	[r+1],FSR0H
		addfsr	0,2
		movsf	[p+0],POSTINC0
		movsf	[p+1],POSTDEC0

;31:			if( (unsigned short)r + ((struct _AllocBlock ram *)r)->Length + 2 == (unsigned short)p )

		;movsf	[r+0],FSR0L
		;movsf	[r+1],FSR0H
		subfsr	0,2

		movf	POSTINC0,w,ACCESS
		addwf	[r+0],w
		movwf	PRODL,ACCESS
		movf	POSTDEC0,w,ACCESS
		addwfc	[r+1],w
		movwf	PRODH,ACCESS

		movlw	0x02
		addwf	PRODL,w,ACCESS
		xorwf	[p+0],w
		bnz	xa68e

		movlw	0x00
		addwfc	PRODH,w,ACCESS
		xorwf	[p+1],w
		bnz	xa68e

;32:				{
;34:				((struct _AllocBlock ram *)r)->Length	+= p->Length + 2;
;33:				((struct _AllocBlock ram *)r)->Next	 = p->Next;

		movsf	[p+0],FSR0L		; FSR0 = p;
		movsf	[p+1],FSR0H

		movlw	0x02			; Aux2 = p->Length + 2;
		addwf	POSTINC0,w,ACCESS
		movwf	[Aux2+0]
		movlw	0x00
		addwfc	POSTINC0,w,ACCESS
		movwf	[Aux2+1]

		movff	POSTINC0,PRODL		; PROD = p->Next;
		movff	POSTINC0,PRODH

		movsf	[r+0],FSR0L		; FSR = r;
		movsf	[r+1],FSR0H

		movf	[Aux2+0],w		; r->Length += Aux2;
		addwf	POSTINC0,f,ACCESS
		movf	[Aux2+1],w
		addwfc	POSTINC0,f,ACCESS

		movff	PRODL,POSTINC0		; r->Next = PROD;
		movff	PRODH,POSTINC0
;35:				}
;36:		
;37:			if( (unsigned short)q + ((struct _AllocBlock ram *)q)->Length + 2 == (unsigned short)r )

xa68e:		movsf	[q+0],FSR0L		; FSR0 = q;
		movsf	[q+1],FSR0H

		movf	POSTINC0,w,ACCESS	; PROD = q->Length;
		addwf	[q+0],w
		movwf	PRODL,ACCESS
		movf	POSTDEC0,w,ACCESS
		addwfc	[q+1],w
		movwf	PRODH,ACCESS

		movlw	0x02			; if( PROD + 2 == r )
		addwf	PRODL,w,ACCESS		;    {
		xorwf	[r+0],w
		bnz	Epilog

		movlw	0x00
		addwfc	PRODH,w,ACCESS
		xorwf	[r+1],w
		bnz	Epilog

;38:				{

;40:				((struct _AllocBlock ram *)q)->Length	+= ((struct _AllocBlock ram *)r)->Length + 2;
;39:				((struct _AllocBlock ram *)q)->Next	 = ((struct _AllocBlock ram *)r)->Next;

		movsf	[r+0],FSR0L		; FSR0 = r;
		movsf	[r+1],FSR0H

		movlw	0x02			; Aux2 = r->Length + 2;
		addwf	POSTINC0,w,ACCESS
		movwf	[Aux2+0]
		movlw	0x00
		addwfc	POSTINC0,w,ACCESS
		movwf	[Aux2+1]

		movff	POSTINC0,PRODL		; PROD = r->Next;
		movff	POSTINC0,PRODH

		movsf	[q+0],FSR0L		; FSR0 = q;
		movsf	[q+1],FSR0H

		movf	[Aux2+0],w		; q->Length += Aux2;
		addwf	POSTINC0,f,ACCESS
		movf	[Aux2+1],w
		addwfc	POSTINC0,f,ACCESS

		movff	PRODL,POSTINC0		; q->Next = PROD;
		movff	PRODH,POSTINC0
;41:				}
;42:			}


Epilog:		RESTORE_INTERRUPTS
Finish:		subfsr	1,LOCALS_SIZE + 1

		movff	POSTDEC1,FSR2H
		movff	INDF1,FSR2L
		return	0
;===============================================================================
		end
;===============================================================================
ON 20081017@9:07:57 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\heap-mgmt.htm&version=13 ON 20081020@6:54:29 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap-mgmt.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\heap-mgmt.htm&version=14 ON 20081020@9:16:41 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/malloc.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\malloc.c.htm&version=0 ON 20081020@9:25:56 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/malloc.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\malloc.c.htm&version=1 ON 20081020@9:26:22 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/malloc.asm.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\malloc.asm.htm&version=0 ON 20081020@9:26:53 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/free.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\free.c.htm&version=0 ON 20081020@9:28:58 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/free.asm.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\free.asm.htm&version=0 ON 20081020@9:29:25 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/__freelist.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\__freelist.c.htm&version=0 ON 20081020@9:29:46 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/__heap.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\__heap.c.htm&version=0 ON 20081020@9:31:41 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/__reclaim_stack.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\__reclaim_stack.c.htm&version=0 ON 20081020@11:19:34 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/heap.h.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\heap.h.htm&version=0 ON 20081020@11:20:00 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/main.c.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\main.c.htm&version=0 ON 20081020@11:20:21 AM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/UsingFreeRTOS.h.htm# James Newton[JMN-EFP-786] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\UsingFreeRTOS.h.htm&version=0 ON 20081020@3:19:31 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/malloc.asm.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\malloc.asm.htm&version=1 ON 20081021@6:23:29 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/index.htm#39742.7662962963 Isaac Marino Bavaresco[IMB-yahoo-J86] Code: /techref/member/IMB-yahoo-J86/SimpleRTOS.htm
Very simple RTOS for Microchip(R) Baseline and Midrange uCs
ON 20081021@6:30:58 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#39742.7714699074 Isaac Marino Bavaresco[IMB-yahoo-J86] Says

by Isaac Marino Bavaresco

ON 20081021@6:32:05 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.htm&version=1 ON 20081021@6:33:58 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#39742.7735763889 Isaac Marino Bavaresco[IMB-yahoo-J86] Code: /techref/member/IMB-yahoo-J86/SimpleRTOS.h.htm




ON 20081021@6:34:51 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.h.htm#39742.7741898148
Isaac Marino Bavaresco[IMB-yahoo-J86] Says

//==============================================================================
// SimpleRTOS - Very simple RTOS for Microchip(R) Baseline and Midrange uCs
// v1.00 (2008-09-23)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
/*
	Notes:	- Works with Hi-Tech PICC v9.60PL2;

			- Assembler optimizations must be OFF for every file that implements
			  task functions (it is better to have the task functions in one or
			  more files with no standard functions, to minimize the un-optimized
			  code length).

			- Every task function must have a call to the macro
			  "TASK_INIT(  );" as the first statement;

			- Every function called directly or indirectly by more than one task
			  must have a call to the macro "FUNC_INIT(  );" as the
			  first statement, unless it doesn't have any parameters nor automatic
			  variables, or all paths through the call-graphs that it belongs have
			  at least one function that calls "FUNC_INIT" before the function is
			  called.

			  Unfortunately this impose certain restrictions when using library
			  functions, unless each library function is called from just one
			  task, or it is present only in call-graphs that at least one
			  function calls "FUNC_INIT" before the library function is called,
			  or you rebuild the library adding the call to "FUNC_INIT" to the
			  library functions that need it.

			- SimpleRTOS functions and macros that may cause a context switch
			  (Eg: Yield, Sleep, DeleteTask (when deleting itself) and
			  MutexTake ) must be called only directly inside the task function,
			  never indirectly by other functions.


	TO DO:	- Find a way to reuse local variables of tasks that are never active
			  at the same time.

			- Implement semaphores.

			- Implement priorities and slice length.

*/
//==============================================================================
#if			!defined __SimpleRTOS_H__
#define		__SimpleRTOS_H__
//==============================================================================
#include 
//==============================================================================
#if			!defined NULL
	#define	NULL 0
#endif	//	!defined NULL
//==============================================================================
#define	USE_BLOCKINGS
//==============================================================================
#define Yield()					{										\
								SavePCLATH	= PCLATH;					\
								asm("global	_SavePCH		" );		\
								asm("global	_SavePCL		" );		\
								asm("global	_Scheduler		" );		\
								asm("movlw	high ($+7)		" );		\
								asm("movwf	_SavePCH		" );		\
								asm("movlw	low ($+5)		" );		\
								asm("movwf	_SavePCL		" );		\
								asm("movlw	high _Scheduler	" );		\
								asm("movwf	10				" );		\
								asm("goto	_Scheduler		" );		\
								PCLATH		= SavePCLATH;				\
								}
//==============================================================================
#define	DeleteTask(t)			{										\
								if( _DeleteTask((t)) )					\
									{									\
									asm( "global _AbortTask	" );		\
									asm( "movlw	high _AbortTask" );		\
									asm( "movwf	10				" );	\
									asm( "goto	_AbortTask	" );		\
									}									\
								}
//==============================================================================
// Put the current task to sleep for 't' ticks. If 't' is greater than 127 then
// the task is suspended (sleeping forever).

#define Sleep(t)				{										\
								_Sleep( t );							\
								Yield();								\
								}
//==============================================================================
#define TASK_INIT(f)			asm( "FNROOT _" #f )
//==============================================================================
#define FUNC_INIT(f)			asm( "FNCALL intlevel1,_" #f );			\
								#pragma interrupt_level 1
//==============================================================================
#define StartRTOS()				{										\
								asm( "global __StartRTOS	" );		\
								asm( "movlw	high __StartRTOS" );		\
								asm( "movwf	10				" );		\
								asm( "goto __StartRTOS		" );		\
								}								
//==============================================================================
#define MutexTake(m,t)			{										\
								if( !_MutexTake( (m), (t) ))			\
									Yield();							\
								}
//==============================================================================
#define	OwnTheMutex(m)			((m)->Owner == CurrentTask)
//==============================================================================
typedef bank2 struct
	{
	/// Saves the high byte of the program counter
	unsigned char		PCH;
	/// Saves the low byte of the program counter
	unsigned char		PCL;
	unsigned char		PCLATH;
	unsigned char		FSR;
	unsigned char		TDelay;

	#ifdef		USE_BLOCKINGS
		void bank2		*PreviousDelayedTask;
		void bank2		*NextDelayedTask;
		void bank2		*DelayList;
	#else	//	USE_BLOCKINGS
		#define	PreviousDelayedTask	Previous
		#define	NextDelayedTask		Next
		#define	DelayList			List
	#endif	//	USE_BLOCKINGS

	#ifdef		USE_SLICE_LENGTH
		unsigned char	SliceLength;
	#endif	//	USE_SLICE_LENGTH

	#ifdef		USE_PRIORITIES
		unsigned char	Priority;
	#endif	//	USE_PRIORITIES
	void bank2			*Previous;
	void bank2			*Next;
	void bank2			*List;
	} TS_Context;
//==============================================================================
typedef bank2 struct
	{
	TS_Context	*Owner;
	TS_Context	*WaitingList;
	} TS_Mutex;
//==============================================================================
extern unsigned char	Ticks;

extern unsigned char	SavePCH;
extern unsigned char	SavePCL;
extern unsigned char	SaveFSR;
extern unsigned char	SavePCLATH;

extern TS_Context		*CurrentTask;
//==============================================================================
void		InitRTOS	( TS_Context *Contexts, unsigned char Number );
void		_StartRTOS	( void );
void		Scheduler	( void );
void		_Sleep		( unsigned char t );
TS_Context	*CreateTask	( void(*TaskFunc)(void) );
bit			_DeleteTask	( TS_Context *Task );
bit			ResumeTask	( TS_Context *Task );
bit			_MutexTake	( TS_Mutex *Mutex, unsigned char t );
bit			MutexGive	( TS_Mutex *Mutex );
//==============================================================================
#endif	//	!defined __SimpleRTOS_H__
//==============================================================================
ON 20081021@6:47:40 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.h.htm# Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference: http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.h.htm&version=1 ON 20081021@6:49:40 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#39742.7844791667 Isaac Marino Bavaresco[IMB-yahoo-J86] Code: /techref/member/IMB-yahoo-J86/SimpleRTOS.c.htm




ON 20081021@6:50:55 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.c.htm#39742.7853472222
Isaac Marino Bavaresco[IMB-yahoo-J86] Says

//==============================================================================
// SimpleRTOS - Very simple RTOS for Microchip(R) Baseline and Midrange uCs
// v1.00 (2008-09-23)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
/*
	Notes:	- Works with Hi-Tech PICC v9.60PL2;

			- Assembler optimizations must be OFF for every file that implements
			  task functions (it is better to have the task functions in one or
			  more files with no standard functions, to minimize the un-optimized
			  code length).

			- Every task function must have a call to the macro
			  "TASK_INIT(  );" as the first statement;

			- Every function called directly or indirectly by more than one task
			  must have a call to the macro "FUNC_INIT(  );" as the
			  first statement, unless it doesn't have any parameters nor automatic
			  variables, or all paths through the call-graphs that it belongs have
			  at least one function that calls "FUNC_INIT" before the function is
			  called.

			  Unfortunately this impose certain restrictions when using library
			  functions, unless each library function is called from just one
			  task, or it is present only in call-graphs that at least one
			  function calls "FUNC_INIT" before the library function is called,
			  or you rebuild the library adding the call to "FUNC_INIT" to the
			  library functions that need it.

			- SimpleRTOS functions and macros that may cause a context switch
			  (Eg: Yield, Sleep, DeleteTask (when deleting itself) and
			  MutexTake ) must be called only directly inside the task function,
			  never indirectly by other functions.


	TO DO:	- Find a way to reuse local variables of tasks that are never active
			  at the same time.

			- Implement semaphores.

			- Implement priorities and slice length.

*/
//==============================================================================
#include 
#include 
#include "SimpleRTOS.h"
//==============================================================================

// Points to the context of the current task.
TS_Context	*CurrentTask		= NULL;

// Points to the head of the unused contexts list. This list is organized as a
// single-linked linear list.
TS_Context	*bank2 FreeContexts	= NULL;

// Points to the head of the running tasks contexts list. This list is organized
// as a double-linked circular list.
TS_Context	*bank2 RunningTasks	= NULL;

// Points to the head of the delayed tasks contexts list. This list is organized
// as a double-linked linear list.
TS_Context	*bank2 DelayedTasks	= NULL;
//==============================================================================
// Tick counter, counts to 255 and roll-over to zero.
unsigned char	Ticks;

// Temporary storage for PCH during the context switching.
unsigned char	SavePCH;
// Temporary storage for PCL during the context switching.
unsigned char	SavePCL;
// Temporary storage for FSR during the context switching.
unsigned char	SaveFSR;
// Temporary storage for PCLATH during the context switching.
unsigned char	SavePCLATH;

// Signals that the running tasks contexts list was already changed by a Sleep.
bit				AlreadySwitched		= 0;
//==============================================================================
// Removes a task from any double-linked list.
void RemoveTaskFromList( TS_Context *Task )
	{
	TS_Context	* bank2 *List;
	TS_Context	*Previous, *Next;

	// Make 'List' point to the pointer to the head of the list.
	List			= Task->List;
	
	// Mark the task as not belonging to any list.
	Task->List		= NULL;

	// Make 'Previous' point to the task that precedes this one in the list (if any).
	Previous		= Task->Previous;

	// Un-link the task from the list.
	Task->Previous	= NULL;

	// Make 'Next' point to the task that follows this one in the list (if any).
	Next			= Task->Next;

	// Un-link the task from the list.
	Task->Next		= NULL;

	// The task is the last one in a circular list...
	if( Previous == Task )
		{
		// ... just remove it from the list.
		*List		= NULL;
		// Finished
		return;
		}

	// The task is the head of the list
	if( *List == Task )
		// Make the next task (if any) be the head of the list.
		*List	= Next;

	// If there is a previous task...
	if( Previous != NULL )
		// ... make it point to the task that follows this one in the list (if any).
		Previous->Next	= Next;

	// If there is a next task...
	if( Next != NULL )
		// ... make it point to the task that precedes this one in the list (if any).
		Next->Previous	= Previous;
	}
//==============================================================================
// If we are not using mutexes or semaphores, we don't need the following function
#if			defined USE_BLOCKINGS

void RemoveTaskFromDelayList( TS_Context *Task )
	{
	TS_Context	*PreviousDelayedTask, *NextDelayedTask;
	
	PreviousDelayedTask	= Task->PreviousDelayedTask;
	NextDelayedTask		= Task->NextDelayedTask;

	// If this task is the first one in the list of delayed tasks...
	if( PreviousDelayedTask == NULL )
		// ... make the next task in the list (if any) be the first.
		DelayedTasks	= NextDelayedTask;
	else
		// ... else make the task before this one in the list point to the task following this one (if any).
		PreviousDelayedTask->NextDelayedTask	= NextDelayedTask;

	// If there is a task after this one in the list...
	if( NextDelayedTask != NULL )
		// ... make it point to the task before this one in the list (if any).
		NextDelayedTask->PreviousDelayedTask	= PreviousDelayedTask;

	// Mark this task as not having a previous one in the delayed tasks list.
	Task->PreviousDelayedTask	= NULL;
	// Mark this task as not having a next one in the delayed tasks list.
	Task->NextDelayedTask		= NULL;
	// Mark this task as not belonging to the delayed tasks list.
	Task->DelayList				= NULL;
	}

#endif	//	defined USE_BLOCKINGS
//==============================================================================
void InsertTaskInCircularList( TS_Context *Task, TS_Context * bank2 *List )
	{
	TS_Context *First, *Last;

	// Mark the task as belonging to the list.
	Task->List	= List;

	// The list is empty...
	if( *List == NULL )
		{
		// ... insert the task into the list.
		*List			= Task;
		// The list is circular, the task is the previous of itself.
		Task->Previous	= Task;
		// The list is circular, the task is the next of itself.
		Task->Next		= Task;
		}
	else
		{
		// Make 'First' point to the first element in the list.
		First			= *List;
		// The last element of a circular list is the element before the first.
		Last			= First->Previous;
		// We are inserting at the end, this element becomes the last one.
		First->Previous	= Task;
		Task->Next		= First;
		Last->Next		= Task;
		Task->Previous	= Last;
		}
	}
//==============================================================================
void InsertTaskInDelayList( TS_Context *Task, unsigned char Time )
	{
	TS_Context *p, *q, *Next;
	unsigned char t;

	// Set the new task's time to wake.
	Task->TDelay	= Time;
	// Make the new task belong to the delayed tasks list.
	Task->DelayList	= &DelayedTasks;

	// The list is empty...
	if( DelayedTasks == NULL )
		{
		// ... just insert the task into the list.
		DelayedTasks				= Task;
		// The list is linear, there is no previous task.
		Task->PreviousDelayedTask	= NULL;
		// The list is linear, there is no next task.
		Task->NextDelayedTask		= NULL;
		}
	// The list is not empty...
	else
		{
		// ... make 'p' point to the first element.
		p = DelayedTasks;
		// Get the first element's time to wake.
		t = p->TDelay;
		// The time to wake of the new task is less than the first element's...
		if( (unsigned char)(Time - t) > 0x7f )
			{
			// ... insert the task as the first element.
			DelayedTasks				= Task;
			// The task is now the first element, there is no previous one.
			Task->PreviousDelayedTask	= NULL;
			// The former first element is now the next one of this task.
			Task->NextDelayedTask		= p;
			// This task is now the previous one of the former first element.
			p->PreviousDelayedTask		= Task;
			}
		// We need to find where the task is to be inserted...
		else
			{
			// ... iterate through the remainig elements of the list (if any).
			for( q = p->NextDelayedTask; q != NULL; q = q->NextDelayedTask )
				{
				// Get the time to wake of the task pointed to by 'q'.
				t = q->TDelay;
				// The time to wake of the new task if less than the one pointed to by 'q'...
				if( (unsigned char)(Time - t) >= 0x7f )
					// ... stop.
					break;
				// Advance one element.
				p = q;
				}
			// We are inserting after the element pointed to by 'p'.
			Next						= p->NextDelayedTask;
			Task->PreviousDelayedTask	= p;
			Task->NextDelayedTask		= Next;
			p->NextDelayedTask			= Task;
			// There is a next element...
			if( Next != NULL )
				// ... make it point to the new task.
				Next->PreviousDelayedTask	= Task;
			}
		}
	}
//==============================================================================
// Test to see if it's time to wake the first delayed task.
void CheckDelayList( void )
	{
	TS_Context *p;
	unsigned char t;

	// The delayed tasks list is not empty...
	if(( p = DelayedTasks ) != NULL )
		{
		// Get the first element's time to wake.
		t = DelayedTasks->TDelay;
		// It's time to wake the task...
		if( (signed char)(t - Ticks) <= 0 )
			{
#if			defined USE_BLOCKINGS

			// Remove the task from the dalayed task list.
			RemoveTaskFromDelayList( p );
			// The task was delayed because it was waiting for some event...
			if( p->List != NULL )

#endif	//	defined USE_BLOCKINGS

				// .. remove the task from the event's list.
				RemoveTaskFromList( p );

			// Insert the task at the end of the running tasks list.
			InsertTaskInCircularList( p, &RunningTasks );
			}
		}
	}
//==============================================================================
void _Sleep( unsigned char t )
	{
	// Needed because this function will (or may) be called by more than one task.
	FUNC_INIT( _Sleep );

	// Remove the task from the running tasks list.
	RemoveTaskFromList( CurrentTask );
	// Flag that the running tasks list alread changed.
	AlreadySwitched = 1;
	// The sleep time is less than the maximum...
	if( t < 128 )
		{
		// ... Set the task's time to wake.
		CurrentTask->TDelay = Ticks + t;
		// Insert the task into the delayed tasks list.
		InsertTaskInDelayList( CurrentTask, Ticks + t );
		}

/*	// This may be useful in the future, but is pointless now.
	// The task is being suspended for undeterminated time...
	else
		// ... insert the task into the suspended tasks list.
		InsertTaskInCircularList( CurrentTask, &SuspendedTasks );
*/
	}
//==============================================================================
bit ResumeTask( TS_Context *Task )
	{
	// Needed because this function will (or may) be called by more than one task.
	FUNC_INIT( ResumeTask );

#if			defined USE_BLOCKINGS

	if( Task == NULL || Task->DelayList != &DelayedTasks )
		return 0;
	
	RemoveTaskFromDelayList( Task );

	if( Task->List != NULL )
		RemoveTaskFromList( Task );

#else	//	defined USE_BLOCKINGS

	if( Task == NULL || Task->List != &DelayedTasks )
		return 0;

	RemoveTaskFromList( Task );

#endif	//	defined USE_BLOCKINGS

	InsertTaskInCircularList( Task, &RunningTasks );
	
	return 1;
	}
//==============================================================================
void Scheduler( void )
	{
	// Needed because this function will be called by more than one task.
	FUNC_INIT( Scheduler );
	//--------------------------------------------------------------------------
	// Save the current context
	//--------------------------------------------------------------------------

	// Save current's task FSR before we change it.
	SaveFSR		= FSR;

	// All task control structures are in banks 2 and 3.
	IRP			= 1;
	// Make FSR point to the current task's context.
	FSR			= (ptrdiff_t)CurrentTask;

	// Save the current task's resume address (high byte) into the task's context.
	INDF		= SavePCH;
	FSR++;

	// Save the current task's resume address (low byte) into the task's context.
	INDF		= SavePCL;
	FSR++;

	// Save the current task's PCLATH into the task's context.
	INDF		= SavePCLATH;
	FSR++;

	// Save the current task's FSR into the task's context.
	INDF		= SaveFSR;

	// Make PCLATH point to the current page
	asm( "movlw	high ($+2)			" );
	asm( "movwf	10					" );	// PCLATH

	asm( "global _AbortTask" );
	// Execution will begin here if a task deletes itself.
	asm( "_AbortTask:" );

	//----------------------------------------------------------------------
	// Switch context
	//----------------------------------------------------------------------

	// Stay here while there is no task ready to run.
	do
		CheckDelayList();
	while( RunningTasks == NULL );

	// The previous task itself didn't changed the running tasks list...
	if( !AlreadySwitched )
		// ... switch the task.
		RunningTasks = RunningTasks->Next;
	AlreadySwitched = 0;

	// Make 'CurrentTask' point to the current task's  context.
	CurrentTask	= RunningTasks;
	
	//----------------------------------------------------------------------
	// Restore context
	//----------------------------------------------------------------------

	// Obtain address of current context
	IRP			= 1;
	FSR			= (ptrdiff_t)CurrentTask;

	// Copy "PCH" from the context to PCLATH
	PCLATH		= INDF;
	FSR++;

	SavePCL		= INDF;
	FSR++;

	SavePCLATH	= INDF;
	FSR++;

	// Copy "FSR" from context
	FSR			= INDF;

	// Copy SavePCL to PCL (effectively jumps to the task's resume address).
	PCL			= SavePCL;
	}
//==============================================================================
void ContextInit( TS_Context *Context, void(*TaskFunc)(void) )
	{
	Context->PCH						= (unsigned int)TaskFunc >> 8;
	Context->PCL						= (unsigned int)TaskFunc;
	Context->PCLATH						= (unsigned int)TaskFunc >> 8;
	Context->FSR						= 0;
	Context->TDelay						= 0;
	#ifdef		USE_BLOCKINGS
		Context->PreviousDelayedTask	= 0;
		Context->NextDelayedTask		= 0;
		Context->DelayList				= 0;
	#endif	//	USE_BLOCKINGS
	#ifdef		USE_SLICE_LENGTH
		Context->SliceLength			= 0;
	#endif	//	USE_SLICE_LENGTH

	#ifdef		USE_PRIORITIES
		Context->Priority				= 0;
	#endif	//	USE_PRIORITIES
	Context->Previous					= 0;
	Context->Next						= 0;
	Context->List						= 0;
	}
//==============================================================================
void _StartRTOS( void )
	{
	CurrentTask	= RunningTasks;

	// Obtain address of current context
	IRP			= 1;
	FSR			= (ptrdiff_t)CurrentTask;

	// Copy "PCH" from context to PCLATH
	PCLATH		= INDF;
	FSR++;

	SavePCL		= INDF;
	FSR++;

	SavePCLATH	= INDF;
	FSR++;

	// Copy "FSR" from context
	FSR			= INDF;

	Ticks		= 0;

	// Copy SavePCL to PCL (effectively jumps to the task's start address).
	PCL			= SavePCL;
	}
//==============================================================================
TS_Context *CreateTask( void(*TaskFunc)(void) )
	{
	TS_Context	*p;

	// Needed because this function will (or may) be called by more than one task.
	FUNC_INIT( CreateTask );

	// There is no free context to be used...
	if( FreeContexts == NULL )
		// ... return failure.
		return NULL;

	// Make 'p' point to the first free context.
	p	= FreeContexts;
	// Remove the context from the free list.
	FreeContexts	= FreeContexts->Next;

	// Initializes the context with the new task's address.
	ContextInit( p, TaskFunc );

	// Insert the new task into the running tasks list.
	InsertTaskInCircularList( p, &RunningTasks );

	// Return the address of the new task's context.
	return p;
	}
//==============================================================================
bit _DeleteTask( TS_Context *Task )
	{
	// Needed because this function will (or may) be called by more than one task.
	FUNC_INIT( _DeleteTask );

	// The task is invalid or already deleted...
	if( Task == NULL || Task->List == &FreeContexts )
		// ... finish.
		return 0;

#if			defined USE_BLOCKINGS

	// The task is delayed...
	if( Task->DelayList == &DelayedTasks )
		// ... remove it from the delayed tasks list.
		RemoveTaskFromDelayList( Task );

#endif	//	defined USE_BLOCKINGS

	// The task is waiting for some event...
	if( Task->List != NULL )
		// ... remove it from the event list.
		RemoveTaskFromList( Task );

	// Link the task's context to the free contexts list
	Task->Next		= FreeContexts;
	FreeContexts	= Task;
	// Mark the context as belonging to the free contexts list.
	Task->List		= &FreeContexts;

	// The task is deleting itself...
	if( Task == CurrentTask )
		// ... return a status saying that the task MUST terminate.
		return 1;
	// The task is not deleting itself...
	else
		// ... return a status saying that the task should continue.
		return 0;
	}
//==============================================================================
void InitRTOS( TS_Context *Contexts, unsigned char Number )
	{
	unsigned char i;

	// No contexts to be initialized... The RTOS is useless.
	if( Contexts == NULL || Number == 0 )
		{
		FreeContexts		= NULL;
		return;
		}

	// Initialize all contexts and link them to the free contexts list.
	FreeContexts			= Contexts;
	for( i = 0; i < Number - 1; i++ )
		{
		Contexts[i].Next	= &Contexts[i+1];
		Contexts[i].List	= &FreeContexts;
		}
	Contexts[i].Next	= NULL;
	Contexts[i].List	= &FreeContexts;
	}
//==============================================================================
bit _MutexTake( TS_Mutex *Mutex, unsigned char t )
	{
	// Needed because this function will (or may) be called by more than one task.
	FUNC_INIT( _MutexTake );

	// The mutex has no owner or is already owned by the current task...
	if( Mutex->Owner == NULL || Mutex->Owner == CurrentTask )
		{
		// ... make the current task the owner of the mutex.
		Mutex->Owner	= CurrentTask;
		// Return a status saying that the task doesn't have to yield.
		return 1;
		}
	// The mutex has a owner already and the task is willing to wait...
	else if( t != 0 )
		{
		// ... delay or suspend the task (depending on the value of 't').
		_Sleep( t );
		// Insert te task into the mutex's event list.
		InsertTaskInCircularList( CurrentTask, &Mutex->WaitingList );
		// Return a status saying that te task MUST yield.
		return 0;
		}
	// Return a status saying that the task doesn't have to yield
	// (but it needs to check if it really got the mutex).
	return 1;
	}
//==============================================================================
bit MutexGive( TS_Mutex *Mutex )
	{
	TS_Context *p;

	// Needed because this function will (or may) be called by more than one task.
	FUNC_INIT( MutexGive );

	// The current task doesn't own the mutex...
	if( Mutex->Owner != CurrentTask )
		// ... return failure.
		return 0;

	// There are tasks waiting for the mutex...
	if(( p = Mutex->WaitingList ) != NULL )
		{
		// ... remove the first task from the mutex's event list.
		RemoveTaskFromList( p );
		// The task is in the delayed tasks list also...
		if( p->DelayList == &DelayedTasks )
			// ... remove it.
			RemoveTaskFromDelayList( p );
		// Insert the task into the running tasks list.
		InsertTaskInCircularList( p, &RunningTasks );
		// The task is now the owner of the mutex.
		Mutex->Owner	= p;
		}
	// There are no tasks waiting for the mutex...
	else
		// ... mark the mutex as having no owner.
		Mutex->Owner	= NULL;

	return 1;
	}
//==============================================================================
ON 20081021@6:52:27 PM at page: http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#39742.786400463 Isaac Marino Bavaresco[IMB-yahoo-J86] Code: /techref/member/IMB-yahoo-J86/TestMain.c.htm




ON 20081021@6:53:52 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/TestMain.c.htm#39742.7873842593
Isaac Marino Bavaresco[IMB-yahoo-J86] Says


//==============================================================================
// SimpleRTOS - Very simple RTOS for Microchip(R) Baseline and Midrange uCs
// v1.00 (2008-09-23)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
/*
	Notes:	- Works with Hi-Tech PICC v9.60PL2;

			- Assembler optimizations must be OFF for every file that implements
			  task functions (it is better to have the task functions in one or
			  more files with no standard functions, to minimize the un-optimized
			  code length).

			- Every task function must have a call to the macro
			  "TASK_INIT( <task function name> );" as the first statement;

			- Every function called directly or indirectly by more than one task
			  must have a call to the macro "FUNC_INIT( <function name> );" as the
			  first statement, unless it doesn't have any parameters nor automatic
			  variables, or all paths through the call-graphs that it belongs have
			  at least one function that calls "FUNC_INIT" before the function is
			  called.

			  Unfortunately this impose certain restrictions when using library
			  functions, unless each library function is called from just one
			  task, or it is present only in call-graphs that at least one
			  function calls "FUNC_INIT" before the library function is called,
			  or you rebuild the library adding the call to "FUNC_INIT" to the
			  library functions that need it.

			- SimpleRTOS functions and macros that may cause a context switch
			  (Eg: Yield, Sleep, DeleteTask (when deleting itself) and
			  MutexTake ) must be called only directly inside the task function,
			  never indirectly by other functions.


	TO DO:	- Find a way to reuse local variables of tasks that are never active
			  at the same time.

			- Implement semaphores.

			- Implement priorities and slice length.

*/
//==============================================================================
// Set TAB width to 4 characters
//==============================================================================
//
//							 PIC16F648A
//
//				+-----------------U-----------------+
//				|									|
//		  <-  ==|  1 RA2/AN2/Vref		 AN1/RA1 18 |==  ->
//				|									|
//		  <-  ==|  2 RA3/AN3/CMP1		 AN0/RA0 15 |==  ->
//				|									|
//		  <-  ==|  3 RA4/T0CKI/CMP2		OSC1/RA7 16 |== <x
//				|									|
//		   -> ==|  4 RA5/!MCLR			OSC2/RA6 15 |==  x>
//				|									|
//			  ==|  5 GND					 VCC 14 |==
//				|									|
//		  <-  ==|  6 RB0/INT		   T1OSI/RB7 13 |==  ->
//				|									|
//	  RXD  -> ==|  7 RB1/RX/DT	 T1CKI/T1OSO/RB6 12 |==  ->
//				|									|
//	  TXD <-  ==|  8 RB2/TX/CK				 RB5 11 |==  ->
//				|									|
//		  <-  ==|  9 RB3/CCP1				 RB4 10 |==  ->
//				|									|
//				+-----------------------------------+
//
//
//==============================================================================
#include <pic.h>
#include "SimpleRTOS.h"

void memcpy( const void *dst, const void *src, unsigned char len );
//==============================================================================
__CONFIG( CPD & PROTECT & BORDIS & LVPDIS & MCLRDIS & PWRTEN & WDTEN & HS );
//==============================================================================

#define	MARCADOR_RX	0xd6
#define	MARCADOR_TX	0xb4
#define	TIME_OUT	 200
//==============================================================================
extern volatile unsigned short TMR1		@ 0x00e;
extern volatile unsigned short CCPR1	@ 0x015;
//==============================================================================
#define	CLOCK		20000000ul
#define BAUD_RATE	   19200ul
#define	TICK_RATE		1000ul
#define	COUNTER_RATE	 100ul
//==============================================================================
unsigned char bank1	SerialRXBuffer[32];
unsigned char		SerialRXLength	= 0;
unsigned char		SerialRXInsert	= 0;

unsigned char bank1	SerialTXBuffer[16];
unsigned char		SerialTXLength	= 0;
unsigned char		SerialTXRemove	= 0;

bit					Overrun			= 0;
//==============================================================================
void interrupt ISR( void )
	{
	//--------------------------------------------------------------------------
	if( CCP1IF && CCP1IE )
		{
		Ticks++;
		CCP1IF	= 0;
		}
	//--------------------------------------------------------------------------
	if( RCIF && RCIE )
		{
		if( OERR )
			{
			CREN	= 0;
			CREN	= 1;
			Overrun	= 1;
			}
		if( SerialRXLength < sizeof SerialRXBuffer )
			{
			SerialRXBuffer[SerialRXInsert] = RCREG;
			if( ++SerialRXInsert >= sizeof SerialRXBuffer )
				SerialRXInsert	= 0;
			SerialRXLength++;
			}
		else
			{
			(void)RCREG;
			Overrun	= 1;
			}
		}
	//--------------------------------------------------------------------------
	if( TXIF && TXIE )
		{
		if( SerialTXLength != 0 )
			{
			TXREG	= SerialTXBuffer[SerialTXRemove];
			if( ++SerialTXRemove >= sizeof SerialTXBuffer )
				SerialTXRemove	= 0;
			if( --SerialTXLength == 0 )
				TXIE	= 0;
			}
		else
			TXIE	= 0;
		}
	//--------------------------------------------------------------------------
	}
//==============================================================================
// Receive one char from the UART. If there is no available char, returns -1.

short SerialReceive( void )
	{
	unsigned char c;

	if( SerialRXLength == 0 )
		return -1;
	GIE	= 0;
	c = SerialRXBuffer[ ( SerialRXInsert - SerialRXLength ) & ( sizeof SerialRXBuffer - 1 ) ];
	SerialRXLength--;
	GIE	= 1;
	return (unsigned short)c;
	}
//==============================================================================
bit SerialTransmit( unsigned char c )
	{
	// Needed because this function is called by more than one task.
	FUNC_INIT( SerialTransmit );

	if( SerialTXLength >= sizeof SerialTXBuffer )
		return 0;
	GIE		= 0;
	SerialTXBuffer[ ( SerialTXRemove + SerialTXLength ) & ( sizeof SerialTXBuffer - 1 ) ] = c;
	SerialTXLength++;
	TXIE	= 1;
	GIE		= 1;
	return 1;
	}
//==============================================================================
bit TransmitInProgress( void )
	{
	return SerialTXLength || ! TRMT ? 1 : 0;
	}
//==============================================================================
TS_Context Contexts[6];	// We will have a maximum of 6 simultaneously running tasks.
//==============================================================================
void MainTask( void );

void main( void )
	{
	CMCON	= 0x07;		// Comparators off.
	PORTA	= 0x00;		// All PORTA pins off.
	PORTB	= 0x06;
	TRISA	= 0xe0;
	TRISB	= 0x02;

	SPBRG	= CLOCK / ( 16ul * BAUD_RATE ) - 1;
	TXSTA	= 0x26;		// 0010 0110
	RCSTA	= 0x90;		// 1001 0000

	CCPR1	= CLOCK / (  4ul * TICK_RATE );
	CCP1CON	= 0x0b;		// CCP1 in compare mode.
	TMR1	= 0;
	T1CON	= 0x01;		// Start TMR1.

	PIR1	= 0x00;		// Clear all interrupt flags.
	PIE1	= 0x34;		// Enable CCP1, UART RX and UART TX interrupts.
	INTCON	= 0xc0;		// Enable selected interrupts.

	// Initialize the contexts and the rest of the RTOS.
	InitRTOS( Contexts, sizeof Contexts / sizeof Contexts[0] );

	// Create just one task, it will create the others.
	CreateTask( MainTask );

	// From now, the RTOS will take over.
	StartRTOS();
	}
//==============================================================================




ON 20081021@6:56:10 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#39742.7889930556
Isaac Marino Bavaresco[IMB-yahoo-J86] Code:
/techref/member/IMB-yahoo-J86/TestTasks.c.htm




ON 20081021@6:57:11 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/TestTasks.c.htm#39742.7896990741
Isaac Marino Bavaresco[IMB-yahoo-J86] Says


//==============================================================================
// SimpleRTOS - Very simple RTOS for Microchip(R) Baseline and Midrange uCs
// v1.00 (2008-09-23)
// isaacbavaresco@yahoo.com.br
//==============================================================================
/*
 Copyright (c) 2007-2008, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//==============================================================================
/*
	Notes:	- Works with Hi-Tech PICC v9.60PL2;

			- Assembler optimizations must be OFF for every file that implements
			  task functions (it is better to have the task functions in one or
			  more files with no standard functions, to minimize the un-optimized
			  code length).

			- Every task function must have a call to the macro
			  "TASK_INIT( <task function name> );" as the first statement;

			- Every function called directly or indirectly by more than one task
			  must have a call to the macro "FUNC_INIT( <function name> );" as the
			  first statement, unless it doesn't have any parameters nor automatic
			  variables, or all paths through the call-graphs that it belongs have
			  at least one function that calls "FUNC_INIT" before the function is
			  called.

			  Unfortunately this impose certain restrictions when using library
			  functions, unless each library function is called from just one
			  task, or it is present only in call-graphs that at least one
			  function calls "FUNC_INIT" before the library function is called,
			  or you rebuild the library adding the call to "FUNC_INIT" to the
			  library functions that need it.

			- SimpleRTOS functions and macros that may cause a context switch
			  (Eg: Yield, Sleep, DeleteTask (when deleting itself) and
			  MutexTake ) must be called only directly inside the task function,
			  never indirectly by other functions.


	TO DO:	- Find a way to reuse local variables of tasks that are never active
			  at the same time.

			- Implement semaphores.

			- Implement priorities and slice length.

*/
//==============================================================================

//==============================================================================
// This module MUST HAVE ASSEMBLER OPTIMIZATIONS OFF, because it uses certain
// macros defined in "SimpleRTOS.h".
//==============================================================================


#include <string.h>
#include "SimpleRTOS.h"
//==============================================================================
short	SerialReceive( void );
bit		SerialTransmit( unsigned char c );
bit		TransmitInProgress( void );
//==============================================================================
TS_Mutex	WorthlessMutex = { NULL, NULL };
//==============================================================================
// We cannot add 'FUNC_INIT' to strlen, unless we change and rebuild the library
// (not a bad idea at all), so we 'wrap' it into this function.

size_t strlen_wrapper( const char *s )
	{
	// This produces a silly pre-processor warning, but we need it.
	FUNC_INIT( strlen_wrapper );

	return strlen( s );
	}
//==============================================================================
void MutexTask1( void )
	{
	const unsigned char Message[] = "Hello world!\r\n";
	const unsigned char *p;
	unsigned char		i;

	// Needed by all task functions.
	TASK_INIT( MutexTask1 );

	while( 1 )
		{
		// We will wait undefinitely until we get the mutex.
		MutexTake( &WorthlessMutex, -1 );

		// Usually we would get here only if we got the mutex, testing
		// just to be sure.
		if( OwnTheMutex( &WorthlessMutex ))
			{
			// Transmit the whole string.
			for( i = strlen_wrapper( Message ), p = Message; i; i--, p++ )
				// Transmit one char. While there is no room for new chars...
				while( SerialTransmit( *p ) == 0 )
					// ... sleep.
					Sleep( 1 );

			// Wait for the last byte to be transmitted.
			while( TransmitInProgress() )
				Sleep( 1 );

			// Let's fustigate the other task a little.
			Sleep( 31 );

			// Do not forget to give the mutex back.
			MutexGive( &WorthlessMutex );
			}
		}
	}
//==============================================================================
void MutexTask2( void )
	{
	const unsigned char Message[] = "I took over the world!\r\n";
	const unsigned char *p;
	unsigned char		i;

	// Needed by all task functions.
	TASK_INIT( MutexTask2 );

	while( 1 )
		{
		// Try to take the mutex within a narrow time window
		MutexTake( &WorthlessMutex, 2 );
		// As the other task takes much more time, this one will get
		// the mutex less often.
		if( OwnTheMutex( &WorthlessMutex ))
			{
			// Transmit the whole string.
			for( i = strlen_wrapper( Message ), p = Message; i; i--, p++ )
				// While there is no room for new chars...
				while( SerialTransmit( *p ) == 0 )
					// ... sleep.
					Sleep( 1 );

			// Do not forget to give the mutex back.
			MutexGive( &WorthlessMutex );
			}
		else
			Sleep( 5 );
		}
	}
//==============================================================================
// Sort of a "poor man's" SIGNAL.
bit Die		= 0;

bit	Alive	= 0;
//==============================================================================
void SuicideTask( void )
	{
	unsigned char i;

	// Needed by all task functions.
	TASK_INIT( SuicideTask );

	// Make sure the loop will repeat at least once.
	Die	= 0;

	while( 1 )
		{
		// Somebody told us to die...
		if( Die )
			{
			// Clean-up before exitting.
			RB7		= 0;
			Alive	= 0;
			// Die piggy, die.
			DeleteTask( CurrentTask );
			}

		// Just a silly thing to do.
		// What a lack of imagination!
		RB7	= ! RB7;

		// It would be better if Ticks were 'unsigned short' or 'unsigned long'.
//		for( i = 10; i; i-- )
			Sleep( 2 );
		}
	}
//==============================================================================
void VictimTask( void )
	{
	// Needed by all task functions.
	TASK_INIT( VictimTask );

	while( 1 )
		{
		// Another silly thing.
		RB6		= ! RB6;
		Sleep( 3 );
		}
	}
//==============================================================================
void TaskRX( void )
	{
	TS_Context *Victim = NULL;
	short		i;

	// Needed by all task functions.
	TASK_INIT( TaskRX );

	while( 1 )
		{
		// Wait for a character.
		while(( i = SerialReceive() ) < 0 )
			Sleep( 1 );

		switch( (unsigned char)i )
			{
			// Start the suicide task.
			case 's':
				// We should not create an already created task.
				if( ! Alive )
					{
					// The task was created succesfully...
					if( CreateTask( SuicideTask ))
						// ... flag it.
						Alive	= 1;
					}
				break;

			// Tell the suicide task to die.
			case 'd':
				Die		= 1;
				break;

			// Create the victim task.
			case 'v':
				// If the task is not created...
				if( Victim == NULL )
					// ... create it.
					Victim = CreateTask( VictimTask );
				break;

			// Kill the victim task.
			case 'k':
				// If the task is alive...
				if( Victim != NULL )
					{
					// ... kill it...
					DeleteTask( Victim );
					// ... and flag it.
					Victim	= NULL;
					}
				break;
			}
		}
	}
//==============================================================================
void MainTask( void )
	{
	unsigned long i = 0;

	// Needed by all task functions.
	TASK_INIT( MainTask );

	// Create the other tasks...
	CreateTask( TaskRX );
	CreateTask( MutexTask1 );
	CreateTask( MutexTask2 );

	while( 1 )
		{
		// Somebody have to keep Cerberus happy.
		CLRWDT();

		// Some very computationally intensive calculations.
		i++;

		// Output the results.
		PORTA	= (unsigned char)i;

		// Give a chance for the other tasks, but return ASAP.
		Yield();
		}
	}
//==============================================================================




ON 20081021@6:58:43 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/TestTasks.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\TestTasks.c.htm&version=1



ON 20081021@7:04:44 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.htm&version=6



ON 20081030@12:11:32 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.h.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.h.htm&version=2



ON 20081030@12:12:20 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.c.htm&version=1



ON 20081030@12:42:16 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/TestTasks.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\TestTasks.c.htm&version=2



ON 20081030@12:43:48 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/TestMain.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\TestMain.c.htm&version=1



ON 20081030@12:45:01 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.h.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.h.htm&version=3



ON 20081030@12:46:05 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.c.htm&version=2



ON 20081030@12:46:24 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.c.htm&version=3



ON 20081030@12:46:53 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/SimpleRTOS.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\SimpleRTOS.htm&version=7



ON 20081030@12:48:20 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/malloc.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\malloc.c.htm&version=2



ON 20081030@12:49:05 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/malloc.asm.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\malloc.asm.htm&version=2



ON 20081030@12:49:52 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/free.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\free.c.htm&version=1



ON 20081030@12:50:15 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/free.asm.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\free.asm.htm&version=1



ON 20081030@12:50:43 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/__freelist.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\__freelist.c.htm&version=1



ON 20081030@12:51:17 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/__heap.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\__heap.c.htm&version=1



ON 20081030@12:51:53 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/__reclaim_stack.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\__reclaim_stack.c.htm&version=1



ON 20081030@12:52:21 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/alloc.h.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\alloc.h.htm&version=0



ON 20081030@12:53:08 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/heap.h.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\heap.h.htm&version=1



ON 20081030@12:53:42 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/main.c.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\main.c.htm&version=1



ON 20081030@12:54:06 PM at page:
http://www.piclist.com/techref/member/IMB-yahoo-J86/UsingFreeRTOS.h.htm#
Isaac Marino Bavaresco[IMB-yahoo-J86] edited the page. Difference:
http://www.piclist.com/techref/diff.asp?url=H:\techref\member\IMB-yahoo-J86\UsingFreeRTOS.h.htm&version=1