OpenCores
URL https://opencores.org/ocsvn/openfire2/openfire2/trunk

Subversion Repositories openfire2

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/trunk/rtl/openfire_debug.v
127,7 → 127,14
end
end
`BARREL_SHIFT: $display("error: barrel shift not implemented");
`FSL : $display("error: fsl not implemented");
`FSL : begin
if(~`FSL_nblock) op[1:8] = "n";
if(`FSL_control) op[9:16] = "c";
if(`fsl_get_put) op[17:40] = "put";
else op[17:40] = "get";
rA = 0;
rB_IMM = 3;
end
`FP_OP : $display("error: floating point not implemented");
`DIVIDE : $display("error: divide not implemented");
`IMMEDIATE : begin
236,6 → 243,11
if(rA == 0) arg2[1:32] = " ";
if(rB_IMM == 0) arg3[1:80] = " ";
else if(rB_IMM == 2) arg3[1:32] = registro_especial(`regS_sel_msr);
else if(rB_IMM == 3)
begin
arg3[1:24] = "FSL";
arg3[25:32] = "0" + instruction[2:0];
end
if(rD && rA) arg1[25:32] = ","; // parameter separators
if(rA && rB_IMM) arg2[25:32] = ",";
if(rD && rB_IMM) arg2[25:32] = ",";
/trunk/rtl/openfire_cpu.v
51,6 → 51,10
`ifdef ENABLE_ALIGNMENT_EXCEPTION
dmem_alignment_exception,
`endif
`ifdef FSL_LINK
fsl_s_data, fsl_s_control, fsl_s_exists, fsl_m_full,
fsl_m_data, fsl_m_control, fsl_m_write, fsl_s_read, pc,
`endif
dmem_addr, dmem_data_in, dmem_data_out, // ins/data ports
dmem_we, dmem_re, dmem_input_sel, dmem_done,
imem_addr, imem_data_in, imem_re, imem_done
68,6 → 72,17
`ifdef ENABLE_ALIGNMENT_EXCEPTION
input dmem_alignment_exception;
`endif
`ifdef FSL_LINK
input [31:0] fsl_s_data;
input fsl_s_control;
input fsl_s_exists;
input fsl_m_full;
output [31:0] fsl_m_data;
output fsl_m_control;
output fsl_m_write;
output fsl_s_read;
output [31:0] pc;
`endif
 
output [31:0] dmem_data_out;
output [31:0] dmem_addr;
112,25 → 127,34
wire branch_instr;
 
`ifdef ENABLE_MSR_BIP
wire update_msr_bip;
wire value_msr_bip;
wire update_msr_bip;
wire value_msr_bip;
`endif
`ifdef ENABLE_INTERRUPTS
wire int_ip;
wire int_dc;
wire set_msr_ie;
wire int_ip;
wire int_dc;
wire set_msr_ie;
`endif
`ifdef ENABLE_EXCEPTIONS
wire reset_msr_eip;
wire insert_exception;
wire reset_msr_eip;
wire insert_exception;
`endif
`ifdef ENABLE_OPCODE_EXCEPTION
wire opcode_exception;
wire opcode_exception;
`endif
`ifdef ENABLE_MSR_OPCODES
wire rS_update;
wire rS_update;
`endif
`ifdef FSL_LINK
wire fsl_get;
wire fsl_cmd_vld;
wire fsl_control;
wire fsl_blocking;
 
assign fsl_m_data = {{(32-`D_WIDTH){1'b0}},regA}; // zero pad FSL to 32-bits
assign pc = {{(32-`A_SPACE+2){1'b0}}, pc_exe_rf};
`endif
 
openfire_fetch FETCH (
.stall(stall_fetch),
.clock(clock),
164,6 → 188,12
`ifdef ENABLE_MSR_OPCODES
.rS_update(rs_update),
`endif
`ifdef FSL_LINK
.fsl_get(fsl_get),
.fsl_control(fsl_control),
.fsl_blocking(fsl_blocking),
.fsl_cmd_vld(fsl_cmd_vld),
`endif
.clock(clock),
.stall(stall_decode),
.reset(reset),
214,6 → 244,18
`ifdef ENABLE_MSR_OPCODES
.rS_update(rs_update),
`endif
`ifdef FSL_LINK
.fsl_m_control(fsl_m_control),
.fsl_m_write(fsl_m_write),
.fsl_s_read(fsl_s_read),
.fsl_cmd_vld(fsl_cmd_vld),
.fsl_get(fsl_get),
.fsl_blocking(fsl_blocking),
.fsl_control(fsl_control),
.fsl_s_exists(fsl_s_exists),
.fsl_m_full(fsl_m_full),
.fsl_s_control(fsl_s_control),
`endif
.clock(clock),
.reset(reset),
.stall(stall_exe),
244,6 → 286,9
);
openfire_regfile REGFILE (
`ifdef FSL_LINK
.fsl_s_data(fsl_s_data),
`endif
.reset(reset),
.clock(clock),
.regA_addr(regA_addr),
/trunk/rtl/openfire_fetch.v
83,8 → 83,8
begin
if (reset)
begin
pc_fetch <= 0;
pc_decode <= 0;
pc_fetch <= `RESET_PC_ADDRESS;
pc_decode <= `RESET_PC_ADDRESS;
imem_re <= 1;
instruction <= `NoOp; // Execute NoOp on reset
end
/trunk/rtl/sim_sram256kx16.v
78,12 → 78,16
if(~we_n & ~ce_n & ~lb_n)
begin
meml[addr % MAX_RAM] = io[7:0];
`ifdef SHOW_SRAM_DATA
$display(" write LOW: meml[%d(%d)]=%d", addr, addr % MAX_RAM, meml[addr % MAX_RAM]);
`endif
end
if(~we_n & ~ce_n & ~ub_n)
begin
memh[addr % MAX_RAM] = io[15:8];
`ifdef SHOW_SRAM_DATA
$display(" write HIGH: memh[%d(%d)]=%d", addr, addr % MAX_RAM, memh[addr % MAX_RAM]);
`endif
end
end
 
/trunk/rtl/openfire_define.v
84,9 → 84,14
//`define DEBUG_FETCH
//`define DEBUG_DECODE
//`define DEBUG_EXECUTE
`define DEBUG_FILE_SRAM "..\\sw\\sample2\\sample.rom" // ROM file to be loaded at SRAM base
`define MAX_SIMULATION_SRAM 4096 // in 32 bit words
`define DEBUG_FILE_SRAM "..\\sw\\test-int\\sample.rom" // ROM file to be loaded at SRAM base
`define MAX_SIMULATION_SRAM 8096 // in 32 bit words
//`define SHOW_SRAM_DATA // show sram write contents
 
// start address after a reset
//`define RESET_PC_ADDRESS 32'h0400_0000 // start at sram (only for simulation!!!)
`define RESET_PC_ADDRESS 32'h0000_0000 // default start PC
 
`define ENABLE_INTERRUPTS // enable interrupt handling & MSR[IE] bit
//`define ENABLE_MSR_BIP // enables MSR[BIP] processing
`define ENABLE_MSR_OPCODES // opcodes to manage MS registers (mfs, msrclr, msrset, mts)
96,7 → 101,7
//`define ENABLE_ALIGNMENT_EXCEPTION // generates exception on memory read/write unalignment
//`define ENABLE_OPCODE_EXCEPTION // generates exception on invalid opcode
`endif
//`define FSL_LINK
//`define FSL_LINK // enable FSL link opcodes (one port only)
 
// Optional CMPU instruction requires a 32-bit comparator
// To enable CMPU support, leave only one of the following two options uncommented
/trunk/rtl/openfire_execute.v
75,6 → 75,11
`ifdef ENABLE_ALIGNMENT_EXCEPTION
dmem_alignment_exception,
`endif
`ifdef FSL_LINK
fsl_m_control, fsl_m_write, fsl_s_read,
fsl_cmd_vld, fsl_get, fsl_blocking, fsl_control, //FSL
fsl_m_full, fsl_s_control, fsl_s_exists,
`endif
clock, reset, stall, // top level
immediate, pc_exe, alu_inputA_sel, alu_inputB_sel, // inputs
alu_inputC_sel, alu_fns_sel, comparator_fns_sel,
129,6 → 134,18
`ifdef ENABLE_ALIGNMENT_EXCEPTION
input dmem_alignment_exception;
`endif
`ifdef FSL_LINK
input fsl_get;
input fsl_control;
input fsl_blocking;
input fsl_cmd_vld;
input fsl_s_control; //From FSL
input fsl_s_exists;
input fsl_m_full;
output fsl_m_control;
output fsl_m_write;
output fsl_s_read;
`endif
 
// From REGFILE
input [31:0] regA;
157,6 → 174,13
reg alu_c_input;
reg MSB_signed_compare;
 
`ifdef FSL_LINK
reg fsl_complete;
reg fsl_m_write;
reg fsl_s_read;
reg fsl_m_control;
`endif
 
wire alu_multicycle_instr;
wire alu_multicycle_instr_complete;
wire multicycle_instr;
193,14 → 217,10
~MSR[`MSR_EIP] & // no Exception in Progress
`endif
`ifdef ENABLE_MSR_BIP
~MSR[`MSR_BIP] & ( // no Break in Progress
~MSR[`MSR_BIP] & // no Break in Progress
`endif
~int_ip | set_msr_ie // not interrupt in progress
`ifdef ENABLE_MSR_BIP // and interrupts are enabled
)
`endif
;
`endif
(~int_ip | set_msr_ie); // not interrupt in progress
`endif // and interrupts are enabled
 
assign branch_taken = branch_instr ? compare_out : 0;
assign pc_branch = alu_out_internal[`A_SPACE+1:0]; // ALU calculates next instr address
215,8 → 235,16
assign memory_instr = we_load | we_store;
assign memory_instr_complete = memory_instr & dmem_done;
 
assign multicycle_instr = memory_instr | alu_multicycle_instr;
assign multicycle_instr_complete = memory_instr_complete | alu_multicycle_instr_complete;
assign multicycle_instr =
`ifdef FSL_LINK
fsl_cmd_vld |
`endif
memory_instr | alu_multicycle_instr;
assign multicycle_instr_complete =
`ifdef FSL_LINK
fsl_complete |
`endif
memory_instr_complete | alu_multicycle_instr_complete;
 
assign instr_complete = ~multicycle_instr | multicycle_instr_complete;
assign we_regfile = (we_load & dmem_done) | alu_multicycle_instr_complete;
261,6 → 289,11
`ifdef ENABLE_MSR_BIP
MSR[`MSR_BIP`] <= 0; // Break In Progress
`endif
`ifdef FSL_LINK
fsl_complete <= 0;
fsl_m_write <= 0;
fsl_s_read <= 0;
`endif
end
else if (~stall)
begin
306,7 → 339,54
if ((alu_fns_sel == `ALU_shiftR_arth) | (alu_fns_sel == `ALU_shiftR_log) |
(alu_fns_sel == `ALU_shiftR_c))
MSR[`MSR_C] <= regA[0];
`ifdef FSL_LINK
// FSL get & put commands
// Reset control signals after write / read
if ((fsl_cmd_vld & fsl_complete) | ~fsl_cmd_vld)
begin
fsl_s_read <= 0;
fsl_complete <= 0;
fsl_m_write <= 0;
end
else if (fsl_cmd_vld & ~fsl_get & ~fsl_blocking) // nonblocking put
begin
fsl_complete <= 1;
MSR[`MSR_C] <= fsl_m_full; //**CHECK**
if (~fsl_m_full)
begin
fsl_m_write <= 1;
fsl_m_control <= fsl_control;
end
end
else if (fsl_cmd_vld & fsl_get & ~fsl_blocking) // nonblocking get
begin
fsl_complete <= 1;
fsl_s_read <= 1;
MSR[`MSR_C] <= ~fsl_s_exists; //**CHECK**
if (fsl_s_exists)
we_load_dly <= 1;
if (fsl_s_control == fsl_control)
MSR[`MSR_FSL_Err] <= 0; // MSR[4] = FSL_Error bit
else
MSR[`MSR_FSL_Err] <= 1;
end
else if (fsl_cmd_vld & ~fsl_get & ~fsl_m_full & fsl_blocking) // blocking put
begin
fsl_complete <= 1;
fsl_m_write <= 1;
fsl_m_control <= fsl_control;
end
else if (fsl_cmd_vld & fsl_get & fsl_s_exists & fsl_blocking) // blocking get
begin
fsl_complete <= 1;
we_load_dly <= 1;
fsl_s_read <= 1;
if (fsl_s_control == fsl_control)
MSR[`MSR_FSL_Err] <= 0;
else
MSR[`MSR_FSL_Err] <= 1;
end
`endif // End FSL extensions
`ifdef DEBUG_EXECUTE
$display("EXECUTE: pc_exe=%x", pc_exe);
`endif
/trunk/rtl/openfire_regfile.v
43,6 → 43,9
`include "openfire_define.v"
 
module openfire_regfile (
`ifdef FSL_LINK
fsl_s_data,
`endif
reset, clock,
regA_addr, regB_addr, regD_addr, result, pc_regfile,
dmem_data, regfile_input_sel, we_regfile,
50,26 → 53,22
regA, regB, regD, enable
);
 
// From top level
input reset;
input reset; // From top level
input clock;
 
// From DECODE
input [4:0] regA_addr;
input [4:0] regA_addr; // From DECODE
input [4:0] regB_addr;
input [4:0] regD_addr;
input [3:0] regfile_input_sel;
input we_alu_branch;
 
// From EXECUTE
input [31:0] result;
input [31:0] result; // From EXECUTE
input [`A_SPACE+1:0] pc_regfile;
input we_regfile;
input enable;
input [31:0] dmem_data; // From DMEM
`ifdef FSL_LINK
input [31:0] fsl_s_data; // From FSL
`endif
 
// From DMEM
input [31:0] dmem_data;
 
output [31:0] regA;
output [31:0] regB;
output [31:0] regD;
91,7 → 90,7
// Input select into REGFILE
always@(
`ifdef FSL_LINK
// todo
fsl_s_data or
`endif
dmem_data or extended_pc or result or regfile_input_sel or write_en or clock
)
103,7 → 102,7
`RF_alu_result: input_data <= result;
`RF_pc: input_data <= extended_pc;
`ifdef FSL_LINK
`RF_fsl: //todo
`RF_fsl: input_data <= fsl_s_data;
`endif
default:
begin
/trunk/rtl/openfire_decode.v
81,6 → 81,9
`ifdef ENABLE_MSR_OPCODES
rS_update,
`endif
`ifdef FSL_LINK
fsl_get, fsl_control, fsl_blocking, fsl_cmd_vld, // fsl signals
`endif
clock, stall, reset, // top level
pc_decode, instruction, flush, // inputs
regA_addr, regB_addr, regD_addr, immediate, // outputs
139,6 → 142,12
`ifdef ENABLE_MSR_OPCODES
output rS_update;
`endif
`ifdef FSL_LINK
output fsl_get;
output fsl_control;
output fsl_blocking;
output fsl_cmd_vld;
`endif
 
// Register All Outputs
reg [31:0] immediate;
176,6 → 185,12
`ifdef ENABLE_MSR_OPCODES
reg rS_update;
`endif
`ifdef FSL_LINK
reg fsl_get;
reg fsl_control;
reg fsl_blocking;
reg fsl_cmd_vld;
`endif
 
// Internal registers
reg [15:0] imm; // contains imm value from IMM instr
226,6 → 241,12
`ifdef ENABLE_MSR_OPCODES
rS_update <= 0;
`endif
`ifdef FSL_LINK
fsl_control <= 0;
fsl_get <= 0;
fsl_blocking <= 0;
fsl_cmd_vld <= 0;
`endif
`ifdef DEBUG_DECODE
$display("DECODE RESET/FLUSH: pc_exe=%x", pc_exe);
`endif
269,6 → 290,12
`ifdef ENABLE_MSR_OPCODES
rS_update <= 0;
`endif
`ifdef FSL_LINK
fsl_control <= 0;
fsl_get <= 0;
fsl_blocking <= 0;
fsl_cmd_vld <= 0;
`endif
`ifdef ENABLE_OPCODE_EXCEPTION
// CPU asks to insert exception break: "brali r17,0x20"
if(insert_exception)
420,7 → 447,14
end
`ifdef FSL_LINK
`FSL:
$display("ERROR! FSL not implemented");
begin
fsl_control <= `FSL_control;
fsl_get <= ~`fsl_get_put;
fsl_blocking <= ~`FSL_nblock;
fsl_cmd_vld <= 1;
we_alu_branch <= 0;
regfile_input_sel <= `RF_fsl;
end
`endif
`ifdef MUL
`MULTIPLY:
/trunk/sw/lib/uart1_readline.c
0,0 → 1,12
#include "openfire.h"
 
void uart1_readline(char *buffer)
{
char tmp;
do
{
*(buffer++) = tmp = uart1_readchar();
uart1_printchar(tmp);
} while(tmp != 0x0 && tmp != '\n' && tmp != '\r');
}
 
/trunk/sw/lib/uart1_printline.c
0,0 → 1,6
#include "openfire.h"
 
void uart1_printline(char *txt)
{
while( *(unsigned char *)txt ) uart1_printchar( (unsigned char) *(txt++));
}
/trunk/sw/lib/__errno.c
0,0 → 1,9
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
 
/* errno handling in a reentrant way *TODO?* */
int *__errno(void)
{
return &errno;
}
/trunk/sw/lib/puthexstring.c
0,0 → 1,19
#include "openfire.h"
 
static char puthexchar(unsigned n)
{
n &= 0xF;
return n + (n < 10 ? '0' : 'A' - 10);
}
 
void puthexstring(char *string, unsigned number, unsigned size)
{
int n = size - 1;
while(number && n >= 0) // hex 2 ascii right to left
{
string[n] = puthexchar(number & 0xf);
number >>= 4;
n--;
}
while(n >= 0) string[n--] = '0'; // left padding with 0
}
/trunk/sw/lib/uart1_readchar.c
0,0 → 1,7
#include "openfire.h"
 
char uart1_readchar(void)
{
while( ((*(volatile unsigned char *) UARTS_STATUS_REGISTER) & UART1_DATA_PRESENT) == 0 ); // wait a received char
return *(char *) UART1_TXRX_DATA;
}
/trunk/sw/lib/uart1_printchar.c
0,0 → 1,8
#include "openfire.h"
 
// --------- uart #1 functions ----------
void uart1_printchar(unsigned char c)
{
while( (*(volatile unsigned char *) UARTS_STATUS_REGISTER) & UART1_TX_BUFFER_FULL ); // wait empty buffer
*(char *) UART1_TXRX_DATA = c;
}
/trunk/sw/lib/havebyte.c
0,0 → 1,8
#include "openfire.h"
 
/* havebyte() -- poll if a byte is available in the serial port */
int havebyte(void)
{
return (*(volatile unsigned char *)UARTS_STATUS_REGISTER) & UART1_DATA_PRESENT;
}
 
/trunk/sw/lib/inbyte.c
0,0 → 1,10
#include "openfire.h"
 
/* inbyte -- get a byte from the serial port with eco and translates \r --> \n */
unsigned char inbyte(void)
{
unsigned char c = uart1_readchar();
if(c == '\r') c = '\n';
outbyte(c);
return c;
}
/trunk/sw/lib/gethexstring.c
0,0 → 1,31
#include "openfire.h"
 
static unsigned gethexchar(char c)
{
if(c >= 'a') c = c - 'a' + '0' + 10;
else if(c >= 'A') c = c - 'A' + '0' + 10;
return c - '0';
}
 
static unsigned ishexdigit(char c)
{
return (c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F');
}
 
char *gethexstring(char *string, unsigned *value, unsigned maxdigits)
{
unsigned number = 0;
while( ishexdigit( string[0] ) && maxdigits > 0)
{
number <<= 4;
number |= gethexchar(string[0]);
string++;
maxdigits--;
}
*value = number;
return string;
}
/trunk/sw/lib/outbyte.c
0,0 → 1,7
#include "openfire.h"
 
/* outbyte -- shove a byte out the serial port. We wait till the byte */
int outbyte( unsigned char c)
{
uart1_printchar(c);
}
/trunk/sw/lib/Makefile
1,6 → 1,15
all:
mb-gcc -c -mno-xl-soft-mul -c -Wa,-ahlms=uart1io.lst -o uart1io.o uart1io.c
PRJ = io
SRCS = __errno.c inbyte.c outbyte.c havebyte.c uart1_printchar.c uart1_printline.c uart1_readchar.c \
uart1_readline.c gethexstring.c puthexstring.c
OBJS = $(SRCS:.c=.o)
 
lib$(PRJ): $(OBJS)
--rm lib$(PRJ).a
mb-ar q lib$(PRJ).a $(OBJS)
 
$(OBJS): $(SRCS)
mb-gcc -O2 -B. -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
 
clean:
-rm *.o
-rm *.out
12,3 → 21,4
-rm *.srec
-rm *.prom
-rm *.rom
-rm *.a
/trunk/sw/lib/openfire.h
1,43 → 1,63
/* peripherals address and configurations */
/* basic i/o */
/* openfire soc - 20070327 - a.anton */
 
#define SP3SK_GPIO 0x08000000
#ifndef __OPENFIRE_H
#define __OPENFIRE_H
 
#define SP3SK_GPIO_SEGMENTS_N 0x000000FF
#define SP3SK_GPIO_DRIVERS_N 0x00000F00
#define SP3SK_GPIO_PUSHBUTTONS 0x0000F000
#define SP3SK_GPIO_LEDS 0x00FF0000
#define SP3SK_GPIO_SWITCHES 0xFF000000
#define SP3SK_GPIO 0x08000000L
 
#define UARTS_STATUS_REGISTER 0x08000004
#define SP3SK_GPIO_SEGMENTS_N 0x000000FFL
#define SP3SK_GPIO_DRIVERS_N 0x00000F00L
#define SP3SK_GPIO_PUSHBUTTONS 0x0000F000L
#define SP3SK_GPIO_LEDS 0x00FF0000L
#define SP3SK_GPIO_SWITCHES 0xFF000000L
 
#define UART1_DATA_PRESENT 0x00000001
#define UART1_RX_HALF_FULL 0x00000002
#define UART1_RX_FULL 0x00000004
#define UART1_TX_HALF_FULL 0x00000008
#define UART1_TX_BUFFER_FULL 0x00000010
#define UARTS_STATUS_REGISTER 0x08000004L
 
#define UART2_DATA_PRESENT 0x00010000
#define UART2_RX_HALF_FULL 0x00020000
#define UART2_RX_FULL 0x00040000
#define UART2_TX_HALF_FULL 0x00080000
#define UART2_TX_FULL 0x00100000
#define UART1_DATA_PRESENT 0x00000001L
#define UART1_RX_HALF_FULL 0x00000002L
#define UART1_RX_FULL 0x00000004L
#define UART1_TX_HALF_FULL 0x00000008L
#define UART1_TX_BUFFER_FULL 0x00000010L
 
#define UART1_TXRX_DATA 0x08000008
#define UART2_TXRX_DATA 0x0800000C
#define UART2_DATA_PRESENT 0x00010000L
#define UART2_RX_HALF_FULL 0x00020000L
#define UART2_RX_FULL 0x00040000L
#define UART2_TX_HALF_FULL 0x00080000L
#define UART2_TX_FULL 0x00100000L
 
#define PROM_READER 0x08000010
#define PROM_DATA 0x000000FF
#define PROM_REQUEST_SYNC 0x00000100
#define PROM_REQUEST_DATA 0x00000200
#define PROM_SYNCED 0x00000400
#define PROM_DATA_READY 0x00000800
#define UART1_TXRX_DATA 0x08000008L
#define UART2_TXRX_DATA 0x0800000CL
 
#define TIMER1_PORT 0x08000014
#define TIMER1_VALUE 0x7FFFFFFF
#define TIMER1_CONTROL 0x80000000
#define PROM_READER 0x08000010L
#define PROM_DATA 0x000000FFL
#define PROM_REQUEST_SYNC 0x00000100L
#define PROM_REQUEST_DATA 0x00000200L
#define PROM_SYNCED 0x00000400L
#define PROM_DATA_READY 0x00000800L
 
#define INTERRUPT_ENABLE 0x08000018
#define INTERRUPT_TIMER1 0x00000001
#define INTERRUPT_UART1_RX 0x00000002
#define INTERRUPT_UART2_RX 0x00000004
#define TIMER1_PORT 0x08000014L
#define TIMER1_VALUE 0x7FFFFFFFL
#define TIMER1_CONTROL 0x80000000L
 
#define INTERRUPT_ENABLE 0x08000018L
#define INTERRUPT_TIMER1 0x00000001L
#define INTERRUPT_UART1_RX 0x00000002L
#define INTERRUPT_UART2_RX 0x00000004L
 
unsigned char inbyte(void);
int outbyte( unsigned char c);
int havebyte(void);
 
char *gethexstring(char *string, unsigned *value, unsigned maxdigits);
void puthexstring(char *string, unsigned number, unsigned size);
 
void uart1_printchar(unsigned char c);
void uart1_printline(char *txt);
char uart1_readchar(void);
void uart1_readline(char *buffer);
 
int *__errno(void);
 
#endif
/trunk/sw/test-int/sample.c
0,0 → 1,43
#include "openfire.h"
 
// --- prototypes ---
void interrupt_handler(void) __attribute__((interrupt_handler));
 
// -------------------------------------
void interrupt_handler(void)
{
uart1_printchar('.');
}
 
// -------------------------------------
void main(void)
{
int n;
uart1_printline("inicio del test\r\n");
uart1_printline("setting interrupt handler\r\n");
asm volatile ("la r6, r0, interrupt_handler \n\t" \
"sw r6, r1, r0 \n\t" \
"lhu r7, r1, r0 \n\t" \
"shi r7, r0, 0x12 \n\t" \
"shi r6, r0, 0x16 \n\t" \
"la r6, r0, 0x2 \n\t" \
"mts rmsr, r6 \n\t" );
uart1_printline("configure timer1\r\n");
*(unsigned long *) TIMER1_PORT = TIMER1_CONTROL | 50000000L; // pulse each 2 seconds
uart1_printline("enable interrupts for timer1\r\n");
*(unsigned long *) INTERRUPT_ENABLE = INTERRUPT_TIMER1;
 
uart1_printline("working...");
while(1)
{
for(n = 0; n < 1000000; n++);
uart1_printchar('+');
}
}
 
/trunk/sw/test-int/Makefile
0,0 → 1,28
PRJ = sample
CRT = ../crt/crt-sram
SRCS = $(PRJ).c
OBJS = $(SRCS:.c=.o)
LINK = ../link/sp3sk-sram.ld
 
$(PRJ).srec: $(PRJ).out
mb-objcopy -O srec $(PRJ).out $(PRJ).srec
mb-objcopy -O binary $(PRJ).out $(PRJ).bin
..\..\utils\bin2rom $(PRJ).bin $(PRJ).rom
 
$(OBJS): $(SRCS)
mb-gcc -O2 -I../lib -I. -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
 
$(PRJ).out: $(CRT).o $(OBJS)
mb-ld -L ../lib -T $(LINK) -Map=$(PRJ).map -o $(PRJ).out $(CRT).o $(OBJS) -lgcc -lc -lm -lgcc -lio
clean:
-rm *.o
-rm *.out
-rm *.bin
-rm *.v
-rm *.map
-rm *.lst
-rm *.bak
-rm *.srec
-rm *.prom
-rm *.rom
/trunk/sw/crt/crt-bram.s
18,21 → 18,16
# # 0x20 # Imm instr for hw exception address [Hi halfword]
# # 0x24 # Jump instr to hw exception handler [Lo halfword]
 
.globl _start
.globl _start
.align 2
.ent _start
_start: brai _start1
_vector_sw_exception: brai _exception_handler
_vector_interrupt: brai _interrupt_handler
_vector_breakpoint: brai _breakpoint_handler
_vector_hw_exception: brai _hw_exception_handler
 
.align 2
.ent _start
_start:
bri _start1 # 0x00 # reset vector
nop # 0x04
nop # 0x08 # Reserve space for software exception vector
nop # 0x0c
nop # 0x10 # Reserve space for interrupt vector
nop # 0x14
nop # 0x18 # Reserve space for breakpoint vector
nop # 0x1c
nop # 0x18 # Reserve space for hw exception vector
nop # 0x1c
/* ------ crt starts here --------- */
 
_start1: /* Set the Small Data Anchors and the Stack pointer */
la r13, r0, _SDA_BASE_
65,8 → 60,13
nop # fall throught to exit
.end _start
 
_exception_handler:
_interrupt_handler:
_breakpoint_handler:
_hw_exception_handler:
 
.globl exit # exit library call
.ent exit
exit:
bri exit
bri _start1
.end exit
/trunk/sw/crt/crt-sram.s
11,8 → 11,8
.align 2
.ent _start
_start:
nop /* to help simulation external program without block ram */
/* todo : initialize system vectors */
 
/* Set the Small Data Anchors and the Stack pointer */
la r13, r0, _SDA_BASE_
la r2, r0, _SDA2_BASE_
/trunk/sw/crt/Makefile
1,7 → 1,6
all:
mb-as -a=crt-bram.lst -o crt-bram.o crt-bram.s
mb-as -a=crt-sram.lst -o crt-sram.o crt-sram.s
mb-as -a=crt-sram-with-int.lst -o crt-sram-with-int.o crt-sram-with-int.s
 
clean:
-rm *.o
/trunk/sw/freertos/FreeRTOS.h
0,0 → 1,104
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#ifndef INC_FREERTOS_H
#define INC_FREERTOS_H
 
/*
* Include the generic headers required for the FreeRTOS port being used.
*/
#include <stddef.h>
 
/* Basic FreeRTOS definitions. */
#include "projdefs.h"
 
/* Application specific configuration options. */
#include "FreeRTOSConfig.h"
 
/* Definitions specific to the port being used. */
#include "portable.h"
 
/*
* Check all the required application specific macros have been defined.
* These macros are application specific and (as downloaded) are defined
* within FreeRTOSConfig.h.
*/
 
#ifndef configUSE_PREEMPTION
#error Missing definition: configUSE_PREEMPTION should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef configUSE_IDLE_HOOK
#error Missing definition: configUSE_IDLE_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef configUSE_TICK_HOOK
#error Missing definition: configUSE_TICK_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef configUSE_CO_ROUTINES
#error Missing definition: configUSE_CO_ROUTINES should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_vTaskPrioritySet
#error Missing definition: INCLUDE_vTaskPrioritySet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_uxTaskPriorityGet
#error Missing definition: INCLUDE_uxTaskPriorityGet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_vTaskDelete
#error Missing definition: INCLUDE_vTaskDelete should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_vTaskCleanUpResources
#error Missing definition: INCLUDE_vTaskCleanUpResources should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_vTaskSuspend
#error Missing definition: INCLUDE_vTaskSuspend should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_vTaskDelayUntil
#error Missing definition: INCLUDE_vTaskDelayUntil should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef INCLUDE_vTaskDelay
#error Missing definition: INCLUDE_vTaskDelay should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#ifndef configUSE_16_BIT_TICKS
#error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
#endif
 
#endif
/trunk/sw/freertos/heap_2.c
0,0 → 1,235
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*
* A sample implementation of pvPortMalloc() and vPortFree() that permits
* allocated blocks to be freed, but does not combine adjacent free blocks
* into a single larger block.
*
* See heap_1.c and heap_3.c for alternative implementations, and the memory
* management pages of http://www.FreeRTOS.org for more information.
*/
#include <stdio.h>
#include <stdlib.h>
 
#include "FreeRTOS.h"
#include "task.h"
 
/* Setup the correct byte alignment mask for the defined byte alignment. */
#if portBYTE_ALIGNMENT == 4
#define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0003 )
#endif
 
#if portBYTE_ALIGNMENT == 2
#define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0001 )
#endif
 
#if portBYTE_ALIGNMENT == 1
#define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0000 )
#endif
 
#ifndef heapBYTE_ALIGNMENT_MASK
#error "Invalid portBYTE_ALIGNMENT definition"
#endif
 
/* Allocate the memory for the heap. The struct is used to force byte
alignment without using any non-portable code. */
extern void *_HEAP_SIZE;
extern void *_heap;
unsigned char *ucHeap = (unsigned char *) &_heap; /* heap starts here (word aligned) */
 
/* Define the linked list structure. This is used to link free blocks in order
of their size. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} xBlockLink;
 
 
static const unsigned portSHORT heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
 
/* Create a couple of list links to mark the start and end of the list. */
static xBlockLink xStart, xEnd;
 
/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
 
/*
* Insert a block into the list of free blocks - which is ordered by size of
* the block. Small blocks at the start of the list and large blocks at the end
* of the list.
*/
#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \
{ \
xBlockLink *pxIterator; \
size_t xBlockSize; \
\
xBlockSize = pxBlockToInsert->xBlockSize; \
\
/* Iterate through the list until a block is found that has a larger size */ \
/* than the block we are inserting. */ \
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
{ \
/* There is nothing to do here - just iterate to the correct position. */ \
} \
\
/* Update the list to include the block being inserted in the correct */ \
/* position. */ \
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \
pxIterator->pxNextFreeBlock = pxBlockToInsert; \
}
/*-----------------------------------------------------------*/
 
#define prvHeapInit() \
{ \
xBlockLink *pxFirstFreeBlock; \
\
/* xStart is used to hold a pointer to the first item in the list of free */ \
/* blocks. The void cast is used to prevent compiler warnings. */ \
xStart.pxNextFreeBlock = ( void * ) ucHeap; \
xStart.xBlockSize = ( size_t ) 0; \
\
/* xEnd is used to mark the end of the list of free blocks. */ \
xEnd.xBlockSize = (unsigned portLONG) &_HEAP_SIZE; \
xEnd.pxNextFreeBlock = NULL; \
\
/* To start with there is a single free block that is sized to take up the \
entire heap space. */ \
pxFirstFreeBlock = ( void * ) ucHeap; \
pxFirstFreeBlock->xBlockSize = (unsigned portLONG) &_HEAP_SIZE; \
pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \
}
/*-----------------------------------------------------------*/
 
void *pvPortMalloc( size_t xWantedSize )
{
xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
void *pvReturn = NULL;
 
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
initialisation to setup the list of free blocks. */
if( xHeapHasBeenInitialised == pdFALSE )
{
prvHeapInit();
xHeapHasBeenInitialised = pdTRUE;
}
 
/* The wanted size is increased so it can contain a xBlockLink
structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += heapSTRUCT_SIZE;
 
/* Ensure that blocks are always aligned to the required number of bytes. */
if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
}
}
 
if( ( xWantedSize > 0 ) && ( xWantedSize < (unsigned portLONG) &_HEAP_SIZE ) )
{
/* Blocks are stored in byte order - traverse the list from the start
(smallest) block until one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
 
/* If we found the end marker then a block of adequate size was not found. */
if( pxBlock != &xEnd )
{
/* Return the memory space - jumping over the xBlockLink structure
at its start. */
pvReturn = ( void * ) ( ( ( unsigned portCHAR * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
 
/* This block is being returned for use so must be taken our of the
list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
 
/* If the block is larger than required it can be split into two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new block
following the number of bytes requested. The void cast is
used to prevent byte alignment warnings from the compiler. */
pxNewBlockLink = ( void * ) ( ( ( unsigned portCHAR * ) pxBlock ) + xWantedSize );
/* Calculate the sizes of two blocks split from the single
block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
}
}
}
}
xTaskResumeAll();
 
return pvReturn;
}
/*-----------------------------------------------------------*/
 
void vPortFree( void *pv )
{
unsigned portCHAR *puc = ( unsigned portCHAR * ) pv;
xBlockLink *pxLink;
 
if( pv )
{
/* The memory being freed will have an xBlockLink structure immediately
before it. */
puc -= heapSTRUCT_SIZE;
 
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
 
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );
}
xTaskResumeAll();
}
}
/*-----------------------------------------------------------*/
 
/trunk/sw/freertos/semphr.h
0,0 → 1,289
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#include "queue.h"
 
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
 
typedef xQueueHandle xSemaphoreHandle;
 
#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned portCHAR ) 1 )
#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portCHAR ) 0 )
#define semGIVE_BLOCK_TIME ( ( portTickType ) 0 )
 
 
/**
* semphr. h
* <pre>vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )</pre>
*
* <i>Macro</i> that implements a semaphore by using the existing queue mechanism.
* The queue length is 1 as this is a binary semaphore. The data size is 0
* as we don't want to actually store any data - we just want to know if the
* queue is empty or full.
*
* @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.
*
* Example usage:
<pre>
xSemaphoreHandle xSemaphore;
 
void vATask( void * pvParameters )
{
// Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
// This is a macro so pass the variable in directly.
vSemaphoreCreateBinary( xSemaphore );
 
if( xSemaphore != NULL )
{
// The semaphore was created successfully.
// The semaphore can now be used.
}
}
</pre>
* \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
* \ingroup Semaphores
*/
#define vSemaphoreCreateBinary( xSemaphore ) { \
xSemaphore = xQueueCreate( ( unsigned portCHAR ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \
if( xSemaphore != NULL ) \
{ \
xSemaphoreGive( xSemaphore ); \
} \
}
 
/**
* semphr. h
* xSemaphoreTake(
* xSemaphoreHandle xSemaphore,
* portTickType xBlockTime
* )</pre>
*
* <i>Macro</i> to obtain a semaphore. The semaphore must of been created using
* vSemaphoreCreateBinary ().
*
* @param xSemaphore A handle to the semaphore being obtained. This is the
* handle returned by vSemaphoreCreateBinary ();
*
* @param xBlockTime The time in ticks to wait for the semaphore to become
* available. The macro portTICK_RATE_MS can be used to convert this to a
* real time. A block time of zero can be used to poll the semaphore.
*
* @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime
* expired without the semaphore becoming available.
*
* Example usage:
<pre>
xSemaphoreHandle xSemaphore = NULL;
 
// A task that creates a semaphore.
void vATask( void * pvParameters )
{
// Create the semaphore to guard a shared resource.
vSemaphoreCreateBinary( xSemaphore );
}
 
// A task that uses the semaphore.
void vAnotherTask( void * pvParameters )
{
// ... Do other things.
 
if( xSemaphore != NULL )
{
// See if we can obtain the semaphore. If the semaphore is not available
// wait 10 ticks to see if it becomes free.
if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
{
// We were able to obtain the semaphore and can now access the
// shared resource.
 
// ...
 
// We have finished accessing the shared resource. Release the
// semaphore.
xSemaphoreGive( xSemaphore );
}
else
{
// We could not obtain the semaphore and can therefore not access
// the shared resource safely.
}
}
}
</pre>
* \defgroup xSemaphoreTake xSemaphoreTake
* \ingroup Semaphores
*/
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime )
 
/**
* semphr. h
* <pre>xSemaphoreGive( xSemaphoreHandle xSemaphore )</pre>
*
* <i>Macro</i> to release a semaphore. The semaphore must of been created using
* vSemaphoreCreateBinary (), and obtained using sSemaphoreTake ().
*
* This must not be used from an ISR. See xSemaphoreGiveFromISR () for
* an alternative which can be used from an ISR.
*
* @param xSemaphore A handle to the semaphore being released. This is the
* handle returned by vSemaphoreCreateBinary ();
*
* @return pdTRUE if the semaphore was released. pdFALSE if an error occurred.
* Semaphores are implemented using queues. An error can occur if there is
* no space on the queue to post a message - indicating that the
* semaphore was not first obtained correctly.
*
* Example usage:
<pre>
xSemaphoreHandle xSemaphore = NULL;
 
void vATask( void * pvParameters )
{
// Create the semaphore to guard a shared resource.
vSemaphoreCreateBinary( xSemaphore );
 
if( xSemaphore != NULL )
{
if( xSemaphoreGive( xSemaphore ) != pdTRUE )
{
// We would expect this call to fail because we cannot give
// a semaphore without first "taking" it!
}
 
// Obtain the semaphore - don't block if the semaphore is not
// immediately available.
if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )
{
// We now have the semaphore and can access the shared resource.
 
// ...
 
// We have finished accessing the shared resource so can free the
// semaphore.
if( xSemaphoreGive( xSemaphore ) != pdTRUE )
{
// We would not expect this call to fail because we must have
// obtained the semaphore to get here.
}
}
}
}
</pre>
* \defgroup xSemaphoreGive xSemaphoreGive
* \ingroup Semaphores
*/
#define xSemaphoreGive( xSemaphore ) xQueueSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME )
 
/**
* semphr. h
* <pre>
xSemaphoreGiveFromISR(
xSemaphoreHandle xSemaphore,
portSHORT sTaskPreviouslyWoken
)</pre>
*
* <i>Macro</i> to release a semaphore. The semaphore must of been created using
* vSemaphoreCreateBinary (), and obtained using xSemaphoreTake ().
*
* This macro can be used from an ISR.
*
* @param xSemaphore A handle to the semaphore being released. This is the
* handle returned by vSemaphoreCreateBinary ();
*
* @param sTaskPreviouslyWoken This is included so an ISR can make multiple calls
* to xSemaphoreGiveFromISR () from a single interrupt. The first call
* should always pass in pdFALSE. Subsequent calls should pass in
* the value returned from the previous call. See the file serial .c in the
* PC port for a good example of using xSemaphoreGiveFromISR ().
*
* @return pdTRUE if a task was woken by releasing the semaphore. This is
* used by the ISR to determine if a context switch may be required following
* the ISR.
*
* Example usage:
<pre>
#define LONG_TIME 0xffff
#define TICKS_TO_WAIT 10
xSemaphoreHandle xSemaphore = NULL;
 
// Repetitive task.
void vATask( void * pvParameters )
{
for( ;; )
{
// We want this task to run every 10 ticks or a timer. The semaphore
// was created before this task was started
 
// Block waiting for the semaphore to become available.
if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
{
// It is time to execute.
 
// ...
 
// We have finished our task. Return to the top of the loop where
// we will block on the semaphore until it is time to execute
// again.
}
}
}
 
// Timer ISR
void vTimerISR( void * pvParameters )
{
static unsigned portCHAR ucLocalTickCount = 0;
 
// A timer tick has occurred.
 
// ... Do other time functions.
 
// Is it time for vATask () to run?
ucLocalTickCount++;
if( ucLocalTickCount >= TICKS_TO_WAIT )
{
// Unblock the task by releasing the semaphore.
xSemaphoreGive( xSemaphore );
 
// Reset the count so we release the semaphore again in 10 ticks time.
ucLocalTickCount = 0;
}
}
</pre>
* \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
* \ingroup Semaphores
*/
#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken ) xQueueSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken )
 
 
#endif
 
/trunk/sw/freertos/task.h
0,0 → 1,951
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#ifndef TASK_H
#define TASK_H
 
#include "portable.h"
#include "list.h"
 
/*-----------------------------------------------------------
* MACROS AND DEFINITIONS
*----------------------------------------------------------*/
 
#define tskKERNEL_VERSION_NUMBER "V4.2.0"
 
/**
* task. h
*
* Type by which tasks are referenced. For example, a call to xTaskCreate
* returns (via a pointer parameter) an xTaskHandle variable that can then
* be used as a parameter to vTaskDelete to delete the task.
*
* \page xTaskHandle xTaskHandle
* \ingroup Tasks
*/
typedef void * xTaskHandle;
 
/*
* Used internally only.
*/
typedef struct xTIME_OUT
{
portBASE_TYPE xOverflowCount;
portTickType xTimeOnEntering;
} xTimeOutType;
 
/*
* Defines the priority used by the idle task. This must not be modified.
*
* \ingroup TaskUtils
*/
#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0 )
 
/**
* task. h
*
* Macro for forcing a context switch.
*
* \page taskYIELD taskYIELD
* \ingroup SchedulerControl
*/
#define taskYIELD() portYIELD()
 
/**
* task. h
*
* Macro to mark the start of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \page taskENTER_CRITICAL taskENTER_CRITICAL
* \ingroup SchedulerControl
*/
#define taskENTER_CRITICAL() portENTER_CRITICAL()
 
/**
* task. h
*
* Macro to mark the end of a critical code region. Preemptive context
* switches cannot occur when in a critical region.
*
* NOTE: This may alter the stack (depending on the portable implementation)
* so must be used with care!
*
* \page taskEXIT_CRITICAL taskEXIT_CRITICAL
* \ingroup SchedulerControl
*/
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
 
/**
* task. h
*
* Macro to disable all maskable interrupts.
*
* \page taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
* \ingroup SchedulerControl
*/
#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
 
/**
* task. h
*
* Macro to enable microcontroller interrupts.
*
* \page taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS
* \ingroup SchedulerControl
*/
#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
 
 
/*-----------------------------------------------------------
* TASK CREATION API
*----------------------------------------------------------*/
 
/**
* task. h
*<pre>
portBASE_TYPE xTaskCreate(
pdTASK_CODE pvTaskCode,
const portCHAR * const pcName,
unsigned portSHORT usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pvCreatedTask
);</pre>
*
* Create a new task and add it to the list of tasks that are ready to run.
*
* @param pvTaskCode Pointer to the task entry function. Tasks
* must be implemented to never return (i.e. continuous loop).
*
* @param pcName A descriptive name for the task. This is mainly used to
* facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default
* is 16.
*
* @param usStackDepth The size of the task stack specified as the number of
* variables the stack can hold - not the number of bytes. For example, if
* the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
* will be allocated for stack storage.
*
* @param pvParameters Pointer that will be used as the parameter for the task
* being created.
*
* @param uxPriority The priority at which the task should run.
*
* @param pvCreatedTask Used to pass back a handle by which the created task
* can be referenced.
*
* @return pdPASS if the task was successfully created and added to a ready
* list, otherwise an error code defined in the file errors. h
*
* Example usage:
<pre>
// Task to be created.
void vTaskCode( void * pvParameters )
{
for( ;; )
{
// Task code goes here.
}
}
 
// Function that creates a task.
void vOtherFunction( void )
{
unsigned char ucParameterToPass;
xTaskHandle xHandle;
// Create the task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
// Use the handle to delete the task.
vTaskDelete( xHandle );
}
</pre>
* \defgroup xTaskCreate xTaskCreate
* \ingroup Tasks
*/
signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvCreatedTask );
 
/**
* task. h
* <pre>void vTaskDelete( xTaskHandle pxTask );</pre>
*
* INCLUDE_vTaskDelete must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* Remove a task from the RTOS real time kernels management. The task being
* deleted will be removed from all ready, blocked, suspended and event lists.
*
* NOTE: The idle task is responsible for freeing the kernel allocated
* memory from tasks that have been deleted. It is therefore important that
* the idle task is not starved of microcontroller processing time if your
* application makes any calls to vTaskDelete (). Memory allocated by the
* task code is not automatically freed, and should be freed before the task
* is deleted.
*
* See the demo application file death.c for sample code that utilises
* vTaskDelete ().
*
* @param pxTask The handle of the task to be deleted. Passing NULL will
* cause the calling task to be deleted.
*
* Example usage:
<pre>
void vOtherFunction( void )
{
xTaskHandle xHandle;
// Create the task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// Use the handle to delete the task.
vTaskDelete( xHandle );
}
</pre>
* \defgroup vTaskDelete vTaskDelete
* \ingroup Tasks
*/
void vTaskDelete( xTaskHandle pxTask );
 
 
/*-----------------------------------------------------------
* TASK CONTROL API
*----------------------------------------------------------*/
 
/**
* task. h
* <pre>void vTaskDelay( portTickType xTicksToDelay );</pre>
*
* Delay a task for a given number of ticks. The actual time that the
* task remains blocked depends on the tick rate. The constant
* portTICK_RATE_MS can be used to calculate real time from the tick
* rate - with the resolution of one tick period.
*
* INCLUDE_vTaskDelay must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* @param xTicksToDelay The amount of time, in tick periods, that
* the calling task should block.
*
* Example usage:
<pre>
// Wait 10 ticks before performing an action.
// NOTE:
// This is for demonstration only and would be better achieved
// using vTaskDelayUntil ().
void vTaskFunction( void * pvParameters )
{
portTickType xDelay, xNextTime;
 
// Calc the time at which we want to perform the action
// next.
xNextTime = xTaskGetTickCount () + ( portTickType ) 10;
 
for( ;; )
{
xDelay = xNextTime - xTaskGetTickCount ();
xNextTime += ( portTickType ) 10;
 
// Guard against overflow
if( xDelay <= ( portTickType ) 10 )
{
vTaskDelay( xDelay );
}
 
// Perform action here.
}
}
</pre>
* \defgroup vTaskDelay vTaskDelay
* \ingroup TaskCtrl
*/
void vTaskDelay( portTickType xTicksToDelay );
 
/**
* task. h
* <pre>void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );</pre>
*
* INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* Delay a task until a specified time. This function can be used by cyclical
* tasks to ensure a constant execution frequency.
*
* This function differs from vTaskDelay () in one important aspect: vTaskDelay () will
* cause a task to block for the specified number of ticks from the time vTaskDelay () is
* called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed
* execution frequency as the time between a task starting to execute and that task
* calling vTaskDelay () may not be fixed [the task may take a different path though the
* code between calls, or may get interrupted or preempted a different number of times
* each time it executes].
*
* Whereas vTaskDelay () specifies a wake time relative to the time at which the function
* is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to
* unblock.
*
* The constant portTICK_RATE_MS can be used to calculate real time from the tick
* rate - with the resolution of one tick period.
*
* @param pxPreviousWakeTime Pointer to a variable that holds the time at which the
* task was last unblocked. The variable must be initialised with the current time
* prior to its first use (see the example below). Following this the variable is
* automatically updated within vTaskDelayUntil ().
*
* @param xTimeIncrement The cycle time period. The task will be unblocked at
* time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the
* same xTimeIncrement parameter value will cause the task to execute with
* a fixed interface period.
*
* Example usage:
<pre>
// Perform an action every 10 ticks.
void vTaskFunction( void * pvParameters )
{
portTickType xLastWakeTime;
const portTickType xFrequency = 10;
 
// Initialise the xLastWakeTime variable with the current time.
xLastWakeTime = xTaskGetTickCount ();
for( ;; )
{
// Wait for the next cycle.
vTaskDelayUntil( &xLastWakeTime, xFrequency );
 
// Perform action here.
}
}
</pre>
* \defgroup vTaskDelayUntil vTaskDelayUntil
* \ingroup TaskCtrl
*/
void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
 
/**
* task. h
* <pre>unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );</pre>
*
* INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* Obtain the priority of any task.
*
* @param pxTask Handle of the task to be queried. Passing a NULL
* handle results in the priority of the calling task being returned.
*
* @return The priority of pxTask.
*
* Example usage:
<pre>
void vAFunction( void )
{
xTaskHandle xHandle;
// Create a task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
 
// Use the handle to obtain the priority of the created task.
// It was created with tskIDLE_PRIORITY, but may have changed
// it itself.
if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
{
// The task has changed it's priority.
}
 
// ...
 
// Is our priority higher than the created task?
if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
{
// Our priority (obtained using NULL handle) is higher.
}
}
</pre>
* \defgroup uxTaskPriorityGet uxTaskPriorityGet
* \ingroup TaskCtrl
*/
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
 
/**
* task. h
* <pre>void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );</pre>
*
* INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* Set the priority of any task.
*
* A context switch will occur before the function returns if the priority
* being set is higher than the currently executing task.
*
* @param pxTask Handle to the task for which the priority is being set.
* Passing a NULL handle results in the priority of the calling task being set.
*
* @param uxNewPriority The priority to which the task will be set.
*
* Example usage:
<pre>
void vAFunction( void )
{
xTaskHandle xHandle;
// Create a task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
 
// ...
 
// Use the handle to raise the priority of the created task.
vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
 
// ...
 
// Use a NULL handle to raise our priority to the same value.
vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
}
</pre>
* \defgroup vTaskPrioritySet vTaskPrioritySet
* \ingroup TaskCtrl
*/
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
 
/**
* task. h
* <pre>void vTaskSuspend( xTaskHandle pxTaskToSuspend );</pre>
*
* INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* Suspend any task. When suspended a task will never get any microcontroller
* processing time, no matter what its priority.
*
* Calls to vTaskSuspend are not accumulative -
* i.e. calling vTaskSuspend () twice on the same task still only requires one
* call to vTaskResume () to ready the suspended task.
*
* @param pxTaskToSuspend Handle to the task being suspended. Passing a NULL
* handle will cause the calling task to be suspended.
*
* Example usage:
<pre>
void vAFunction( void )
{
xTaskHandle xHandle;
// Create a task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
 
// Use the handle to suspend the created task.
vTaskSuspend( xHandle );
 
// ...
// The created task will not run during this period, unless
// another task calls vTaskResume( xHandle ).
//...
 
// Suspend ourselves.
vTaskSuspend( NULL );
 
// We cannot get here unless another task calls vTaskResume
// with our handle as the parameter.
}
</pre>
* \defgroup vTaskSuspend vTaskSuspend
* \ingroup TaskCtrl
*/
void vTaskSuspend( xTaskHandle pxTaskToSuspend );
 
/**
* task. h
* <pre>void vTaskResume( xTaskHandle pxTaskToResume );</pre>
*
* INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* Resumes a suspended task.
*
* A task that has been suspended by one of more calls to vTaskSuspend ()
* will be made available for running again by a single call to
* vTaskResume ().
*
* @param pxTaskToResume Handle to the task being readied.
*
* Example usage:
<pre>
void vAFunction( void )
{
xTaskHandle xHandle;
// Create a task, storing the handle.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
// ...
 
// Use the handle to suspend the created task.
vTaskSuspend( xHandle );
 
// ...
// The created task will not run during this period, unless
// another task calls vTaskResume( xHandle ).
//...
 
// Resume the suspended task ourselves.
vTaskResume( xHandle );
 
// The created task will once again get microcontroller processing
// time in accordance with it priority within the system.
}
</pre>
* \defgroup vTaskResume vTaskResume
* \ingroup TaskCtrl
*/
void vTaskResume( xTaskHandle pxTaskToResume );
 
/**
* task. h
* <pre>void xTaskResumeFromISR( xTaskHandle pxTaskToResume );</pre>
*
* INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be
* available. See the configuration section for more information.
*
* An implementation of vTaskResume() that can be called from within an ISR.
*
* A task that has been suspended by one of more calls to vTaskSuspend ()
* will be made available for running again by a single call to
* xTaskResumeFromISR ().
*
* @param pxTaskToResume Handle to the task being readied.
*
* \defgroup vTaskResumeFromISR vTaskResumeFromISR
* \ingroup TaskCtrl
*/
portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume );
 
/*-----------------------------------------------------------
* SCHEDULER CONTROL
*----------------------------------------------------------*/
 
/**
* task. h
* <pre>void vTaskStartScheduler( void );</pre>
*
* Starts the real time kernel tick processing. After calling the kernel
* has control over which tasks are executed and when. This function
* does not return until an executing task calls vTaskEndScheduler ().
*
* At least one task should be created via a call to xTaskCreate ()
* before calling vTaskStartScheduler (). The idle task is created
* automatically when the first application task is created.
*
* See the demo application file main.c for an example of creating
* tasks and starting the kernel.
*
* Example usage:
<pre>
void vAFunction( void )
{
// Create at least one task before starting the kernel.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
 
// Start the real time kernel with preemption.
vTaskStartScheduler ();
 
// Will not get here unless a task calls vTaskEndScheduler ()
}
</pre>
*
* \defgroup vTaskStartScheduler vTaskStartScheduler
* \ingroup SchedulerControl
*/
void vTaskStartScheduler( void );
 
/**
* task. h
* <pre>void vTaskEndScheduler( void );</pre>
*
* Stops the real time kernel tick. All created tasks will be automatically
* deleted and multitasking (either preemptive or cooperative) will
* stop. Execution then resumes from the point where vTaskStartScheduler ()
* was called, as if vTaskStartScheduler () had just returned.
*
* See the demo application file main. c in the demo/PC directory for an
* example that uses vTaskEndScheduler ().
*
* vTaskEndScheduler () requires an exit function to be defined within the
* portable layer (see vPortEndScheduler () in port. c for the PC port). This
* performs hardware specific operations such as stopping the kernel tick.
*
* vTaskEndScheduler () will cause all of the resources allocated by the
* kernel to be freed - but will not free resources allocated by application
* tasks.
*
* Example usage:
<pre>
void vTaskCode( void * pvParameters )
{
for( ;; )
{
// Task code goes here.
 
// At some point we want to end the real time kernel processing
// so call ...
vTaskEndScheduler ();
}
}
 
void vAFunction( void )
{
// Create at least one task before starting the kernel.
xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
 
// Start the real time kernel with preemption.
vTaskStartScheduler ();
 
// Will only get here when the vTaskCode () task has called
// vTaskEndScheduler (). When we get here we are back to single task
// execution.
}
</pre>
*
* \defgroup vTaskEndScheduler vTaskEndScheduler
* \ingroup SchedulerControl
*/
void vTaskEndScheduler( void );
 
/**
* task. h
* <pre>void vTaskSuspendAll( void );</pre>
*
* Suspends all real time kernel activity while keeping interrupts (including the
* kernel tick) enabled.
*
* After calling vTaskSuspendAll () the calling task will continue to execute
* without risk of being swapped out until a call to xTaskResumeAll () has been
* made.
*
* Example usage:
<pre>
void vTask1( void * pvParameters )
{
for( ;; )
{
// Task code goes here.
 
// ...
 
// At some point the task wants to perform a long operation during
// which it does not want to get swapped out. It cannot use
// taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
// operation may cause interrupts to be missed - including the
// ticks.
 
// Prevent the real time kernel swapping out the task.
vTaskSuspendAll ();
 
// Perform the operation here. There is no need to use critical
// sections as we have all the microcontroller processing time.
// During this time interrupts will still operate and the kernel
// tick count will be maintained.
 
// ...
 
// The operation is complete. Restart the kernel.
xTaskResumeAll ();
}
}
</pre>
* \defgroup vTaskSuspendAll vTaskSuspendAll
* \ingroup SchedulerControl
*/
void vTaskSuspendAll( void );
 
/**
* task. h
* <pre>portCHAR xTaskResumeAll( void );</pre>
*
* Resumes real time kernel activity following a call to vTaskSuspendAll ().
* After a call to vTaskSuspendAll () the kernel will take control of which
* task is executing at any time.
*
* @return If resuming the scheduler caused a context switch then pdTRUE is
* returned, otherwise pdFALSE is returned.
*
* Example usage:
<pre>
void vTask1( void * pvParameters )
{
for( ;; )
{
// Task code goes here.
 
// ...
 
// At some point the task wants to perform a long operation during
// which it does not want to get swapped out. It cannot use
// taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
// operation may cause interrupts to be missed - including the
// ticks.
 
// Prevent the real time kernel swapping out the task.
vTaskSuspendAll ();
 
// Perform the operation here. There is no need to use critical
// sections as we have all the microcontroller processing time.
// During this time interrupts will still operate and the real
// time kernel tick count will be maintained.
 
// ...
 
// The operation is complete. Restart the kernel. We want to force
// a context switch - but there is no point if resuming the scheduler
// caused a context switch already.
if( !xTaskResumeAll () )
{
taskYIELD ();
}
}
}
</pre>
* \defgroup xTaskResumeAll xTaskResumeAll
* \ingroup SchedulerControl
*/
signed portBASE_TYPE xTaskResumeAll( void );
 
 
/*-----------------------------------------------------------
* TASK UTILITIES
*----------------------------------------------------------*/
 
/**
* task. h
* <PRE>volatile portTickType xTaskGetTickCount( void );</PRE>
*
* @return The count of ticks since vTaskStartScheduler was called.
*
* \page xTaskGetTickCount xTaskGetTickCount
* \ingroup TaskUtils
*/
portTickType xTaskGetTickCount( void );
 
/**
* task. h
* <PRE>unsigned portSHORT uxTaskGetNumberOfTasks( void );</PRE>
*
* @return The number of tasks that the real time kernel is currently managing.
* This includes all ready, blocked and suspended tasks. A task that
* has been deleted but not yet freed by the idle task will also be
* included in the count.
*
* \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks
* \ingroup TaskUtils
*/
unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void );
 
/**
* task. h
* <PRE>void vTaskList( portCHAR *pcWriteBuffer );</PRE>
*
* configUSE_TRACE_FACILITY, INCLUDE_vTaskDelete and INCLUDE_vTaskSuspend
* must all be defined as 1 for this function to be available.
* See the configuration section for more information.
*
* NOTE: This function will disable interrupts for its duration. It is
* not intended for normal application runtime use but as a debug aid.
*
* Lists all the current tasks, along with their current state and stack
* usage high water mark.
*
* Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or
* suspended ('S').
*
* @param pcWriteBuffer A buffer into which the above mentioned details
* will be written, in ascii form. This buffer is assumed to be large
* enough to contain the generated report. Approximately 40 bytes per
* task should be sufficient.
*
* \page vTaskList vTaskList
* \ingroup TaskUtils
*/
void vTaskList( signed portCHAR *pcWriteBuffer );
 
/**
* task. h
* <PRE>void vTaskStartTrace( portCHAR * pcBuffer, unsigned portBASE_TYPE uxBufferSize );</PRE>
*
* Starts a real time kernel activity trace. The trace logs the identity of
* which task is running when.
*
* The trace file is stored in binary format. A separate DOS utility called
* convtrce.exe is used to convert this into a tab delimited text file which
* can be viewed and plotted in a spread sheet.
*
* @param pcBuffer The buffer into which the trace will be written.
*
* @param ulBufferSize The size of pcBuffer in bytes. The trace will continue
* until either the buffer in full, or ulTaskEndTrace () is called.
*
* \page vTaskStartTrace vTaskStartTrace
* \ingroup TaskUtils
*/
void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize );
 
/**
* task. h
* <PRE>unsigned portLONG ulTaskEndTrace( void );</PRE>
*
* Stops a kernel activity trace. See vTaskStartTrace ().
*
* @return The number of bytes that have been written into the trace buffer.
*
* \page usTaskEndTrace usTaskEndTrace
* \ingroup TaskUtils
*/
unsigned portLONG ulTaskEndTrace( void );
 
 
/*-----------------------------------------------------------
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
*----------------------------------------------------------*/
 
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
* INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
* AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
*
* Called from the real time kernel tick (either preemptive or cooperative),
* this increments the tick count and checks if any tasks that are blocked
* for a finite period required removing from a blocked list and placing on
* a ready list.
*/
inline void vTaskIncrementTick( void );
 
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
*
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
*
* Removes the calling task from the ready list and places it both
* on the list of tasks waiting for a particular event, and the
* list of delayed tasks. The task will be removed from both lists
* and replaced on the ready list should either the event occur (and
* there be no higher priority tasks waiting on the same event) or
* the delay period expires.
*
* @param pxEventList The list containing tasks that are blocked waiting
* for the event to occur.
*
* @param xTicksToWait The maximum amount of time that the task should wait
* for the event to occur. This is specified in kernel ticks,the constant
* portTICK_RATE_MS can be used to convert kernel ticks into a real time
* period.
*/
void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait );
 
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
*
* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
*
* Removes a task from both the specified event list and the list of blocked
* tasks, and places it on a ready queue.
*
* xTaskRemoveFromEventList () will be called if either an event occurs to
* unblock a task, or the block timeout period expires.
*
* @return pdTRUE if the task being removed has a higher priority than the task
* making the call, otherwise pdFALSE.
*/
signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList );
 
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
* INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
*
* INCLUDE_vTaskCleanUpResources and INCLUDE_vTaskSuspend must be defined as 1
* for this function to be available.
* See the configuration section for more information.
*
* Empties the ready and delayed queues of task control blocks, freeing the
* memory allocated for the task control block and task stacks as it goes.
*/
void vTaskCleanUpResources( void );
 
/*
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
* INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
* AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
*
* Sets the pointer to the current TCB to the TCB of the highest priority task
* that is ready to run.
*/
inline void vTaskSwitchContext( void );
 
/*
* Return the handle of the calling task.
*/
xTaskHandle xTaskGetCurrentTaskHandle( void );
 
/*
* Capture the current time status for future reference.
*/
void vTaskSetTimeOutState( xTimeOutType *pxTimeOut );
 
/*
* Compare the time status now with that previously captured to see if the
* timeout has expired.
*/
portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType *pxTicksToWait );
 
/*
* Shortcut used by the queue implementation to prevent unnecessary call to
* taskYIELD();
*/
void vTaskMissedYield( void );
 
#endif /* TASK_H */
 
 
 
/trunk/sw/freertos/list.c
0,0 → 1,201
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*
Changes from V1.2.0
 
+ Removed the volatile modifier from the function parameters. This was
only ever included to prevent compiler warnings. Now warnings are
removed by casting parameters where the calls are made.
 
+ prvListGetOwnerOfNextEntry() and prvListGetOwnerOfHeadEntry() have been
removed from the c file and added as macros to the h file.
 
+ uxNumberOfItems has been added to the list structure. This removes the
need for a pointer comparison when checking if a list is empty, and so
is slightly faster.
 
+ Removed the NULL check in vListRemove(). This makes the call faster but
necessitates any application code utilising the list implementation to
ensure NULL pointers are not passed.
 
Changes from V2.0.0
 
+ Double linked the lists to allow faster removal item removal.
 
Changes from V2.6.1
 
+ Make use of the new portBASE_TYPE definition where ever appropriate.
 
Changes from V3.0.0
 
+ API changes as described on the FreeRTOS.org WEB site.
 
Changes from V3.2.4
 
+ Removed the pxHead member of the xList structure. This always pointed
to the same place so has been removed to free a few bytes of RAM.
 
+ Introduced the xMiniListItem structure that does not include the
xListItem members that are not required by the xListEnd member of a list.
Again this was done to reduce RAM usage.
 
+ Changed the volatile definitions of some structure members to clean up
the code where the list structures are used.
 
Changes from V4.0.4
 
+ Optimised vListInsert() in the case when the wake time is the maximum
tick count value.
*/
 
#include <stdlib.h>
#include "FreeRTOS.h"
#include "list.h"
 
/*-----------------------------------------------------------
* PUBLIC LIST API documented in list.h
*----------------------------------------------------------*/
 
void vListInitialise( xList *pxList )
{
/* The list structure contains a list item which is used to mark the
end of the list. To initialise the list the list end is inserted
as the only list entry. */
pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );
 
/* The list end value is the highest possible value in the list to
ensure it remains at the end of the list. */
pxList->xListEnd.xItemValue = portMAX_DELAY;
 
/* The list end next and previous pointers point to itself so we know
when the list is empty. */
pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );
 
pxList->uxNumberOfItems = 0;
}
/*-----------------------------------------------------------*/
 
void vListInitialiseItem( xListItem *pxItem )
{
/* Make sure the list item is not recorded as being on a list. */
pxItem->pvContainer = NULL;
}
/*-----------------------------------------------------------*/
 
void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )
{
volatile xListItem * pxIndex;
 
/* Insert a new list item into pxList, but rather than sort the list,
makes the new list item the last item to be removed by a call to
pvListGetOwnerOfNextEntry. This means it has to be the item pointed to by
the pxIndex member. */
pxIndex = pxList->pxIndex;
 
pxNewListItem->pxNext = pxIndex->pxNext;
pxNewListItem->pxPrevious = pxList->pxIndex;
pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;
pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;
 
/* Remember which list the item is in. */
pxNewListItem->pvContainer = ( void * ) pxList;
 
( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/
 
void vListInsert( xList *pxList, xListItem *pxNewListItem )
{
volatile xListItem *pxIterator;
portTickType xValueOfInsertion;
 
/* Insert the new list item into the list, sorted in ulListItem order. */
xValueOfInsertion = pxNewListItem->xItemValue;
 
/* If the list already contains a list item with the same item value then
the new list item should be placed after it. This ensures that TCB's which
are stored in ready lists (all of which have the same ulListItem value)
get an equal share of the CPU. However, if the xItemValue is the same as
the back marker the iteration loop below will not end. This means we need
to guard against this by checking the value first and modifying the
algorithm slightly if necessary. */
if( xValueOfInsertion == portMAX_DELAY )
{
pxIterator = pxList->xListEnd.pxPrevious;
}
else
{
for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
{
/* There is nothing to do here, we are just iterating to the
wanted insertion position. */
}
}
 
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = ( volatile xListItem * ) pxNewListItem;
 
/* Remember which list the item is in. This allows fast removal of the
item later. */
pxNewListItem->pvContainer = ( void * ) pxList;
 
( pxList->uxNumberOfItems )++;
}
/*-----------------------------------------------------------*/
 
void vListRemove( xListItem *pxItemToRemove )
{
xList * pxList;
 
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/* The list item knows which list it is in. Obtain the list from the list
item. */
pxList = ( xList * ) pxItemToRemove->pvContainer;
 
/* Make sure the index is left pointing to a valid item. */
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
 
pxItemToRemove->pvContainer = NULL;
( pxList->uxNumberOfItems )--;
}
/*-----------------------------------------------------------*/
 
/trunk/sw/freertos/portmacro.h
0,0 → 1,118
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#ifndef PORTMACRO_H
#define PORTMACRO_H
 
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
 
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE portLONG
 
#if( configUSE_16_BIT_TICKS == 1 )
typedef unsigned portSHORT portTickType;
#define portMAX_DELAY ( portTickType ) 0xffff
#else
typedef unsigned portLONG portTickType;
#define portMAX_DELAY ( portTickType ) 0xffffffff
#endif
/*-----------------------------------------------------------*/
 
/* Interrupt control macros. */
void openfire_disable_interrupts(void);
void openfire_enable_interrupts(void);
 
#define portDISABLE_INTERRUPTS() openfire_disable_interrupts()
#define portENABLE_INTERRUPTS() openfire_enable_interrupts()
 
/*-----------------------------------------------------------*/
 
/* Critical section macros. */
void vPortEnterCritical( void );
void vPortExitCritical( void );
#define portENTER_CRITICAL() \
{ \
extern unsigned portBASE_TYPE uxCriticalNesting; \
portDISABLE_INTERRUPTS(); \
uxCriticalNesting++; \
}
#define portEXIT_CRITICAL() \
{ \
extern unsigned portBASE_TYPE uxCriticalNesting; \
/* Interrupts are disabled, so we can */ \
/* access the variable directly. */ \
uxCriticalNesting--; \
if( uxCriticalNesting == 0 ) \
{ \
/* The nesting has unwound and we \
can enable interrupts again. */ \
portENABLE_INTERRUPTS(); \
} \
}
 
/*-----------------------------------------------------------*/
 
/* Task utilities. */
void vPortYield( void );
#define portYIELD() vPortYield()
 
void vTaskSwitchContext();
#define portYIELD_FROM_ISR() vTaskSwitchContext()
/*-----------------------------------------------------------*/
 
/* Hardware specifics. */
#define portBYTE_ALIGNMENT 4
#define portSTACK_GROWTH ( -1 )
#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
#define portNOP() asm volatile ( "nop" )
/*-----------------------------------------------------------*/
 
/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
 
#endif /* PORTMACRO_H */
/trunk/sw/freertos/portable.h
0,0 → 1,72
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http:www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http:www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*-----------------------------------------------------------
* Portable layer API. Each function must be defined for each port.
*----------------------------------------------------------*/
 
#ifndef PORTABLE_H
#define PORTABLE_H
 
/* Include the macro file relevant to the port being used. */
#include "portmacro.h"
 
/*
* Setup the stack of a new task so it is ready to be placed under the
* scheduler control. The registers have to be placed on the stack in
* the order that the port expects to find them.
*/
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters );
 
/*
* Map to the memory management routines required for the port.
*/
void *pvPortMalloc( size_t xSize );
void vPortFree( void *pv );
void vPortInitialiseBlocks( void );
 
/*
* Setup the hardware ready for the scheduler to take control. This generally
* sets up a tick interrupt and sets timers for the correct tick frequency.
*/
portBASE_TYPE xPortStartScheduler( void );
 
/*
* Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
* the hardware is left in its original condition after the scheduler stops
* executing.
*/
void vPortEndScheduler( void );
 
 
#endif /* PORTABLE_H */
 
/trunk/sw/freertos/list.h
0,0 → 1,270
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*
* This is the list implementation used by the scheduler. While it is tailored
* heavily for the schedulers needs, it is also available for use by
* application code.
*
* xLists can only store pointers to xListItems. Each xListItem contains a
* numeric value (xItemValue). Most of the time the lists are sorted in
* descending item value order.
*
* Lists are created already containing one list item. The value of this
* item is the maximum possible that can be stored, it is therefore always at
* the end of the list and acts as a marker. The list member pxHead always
* points to this marker - even though it is at the tail of the list. This
* is because the tail contains a wrap back pointer to the true head of
* the list.
*
* In addition to it's value, each list item contains a pointer to the next
* item in the list (pxNext), a pointer to the list it is in (pxContainer)
* and a pointer to back to the object that contains it. These later two
* pointers are included for efficiency of list manipulation. There is
* effectively a two way link between the object containing the list item and
* the list item itself.
*
*
* \page ListIntroduction List Implementation
* \ingroup FreeRTOSIntro
*/
 
 
#ifndef LIST_H
#define LIST_H
 
/*
* Definition of the only type of object that a list can contain.
*/
struct xLIST_ITEM
{
portTickType xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
volatile struct xLIST_ITEM * pxNext; /*< Pointer to the next xListItem in the list. */
volatile struct xLIST_ITEM * pxPrevious;/*< Pointer to the previous xListItem in the list. */
void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
void * pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
};
typedef struct xLIST_ITEM xListItem; /* For some reason lint wants this as two separate definitions. */
 
struct xMINI_LIST_ITEM
{
portTickType xItemValue;
volatile struct xLIST_ITEM *pxNext;
volatile struct xLIST_ITEM *pxPrevious;
};
typedef struct xMINI_LIST_ITEM xMiniListItem;
 
/*
* Definition of the type of queue used by the scheduler.
*/
typedef struct xLIST
{
volatile unsigned portBASE_TYPE uxNumberOfItems;
volatile xListItem * pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */
volatile xMiniListItem xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
} xList;
 
/*
* Access macro to set the owner of a list item. The owner of a list item
* is the object (usually a TCB) that contains the list item.
*
* \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
* \ingroup LinkedList
*/
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( pxListItem )->pvOwner = ( void * ) pxOwner
 
/*
* Access macro to set the value of the list item. In most cases the value is
* used to sort the list in descending order.
*
* \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( pxListItem )->xItemValue = xValue
 
/*
* Access macro the retrieve the value of the list item. The value can
* represent anything - for example a the priority of a task, or the time at
* which a task should be unblocked.
*
* \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
* \ingroup LinkedList
*/
#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
 
/*
* Access macro to determine if a list contains any items. The macro will
* only have the value true if the list is empty.
*
* \page listLIST_IS_EMPTY listLIST_IS_EMPTY
* \ingroup LinkedList
*/
#define listLIST_IS_EMPTY( pxList ) ( ( pxList )->uxNumberOfItems == ( unsigned portBASE_TYPE ) 0 )
 
/*
* Access macro to return the number of items in the list.
*/
#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
 
/*
* Access function to obtain the owner of the next entry in a list.
*
* The list member pxIndex is used to walk through a list. Calling
* listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
* and returns that entries pxOwner parameter. Using multiple calls to this
* function it is therefore possible to move through every item contained in
* a list.
*
* The pxOwner parameter of a list item is a pointer to the object that owns
* the list item. In the scheduler this is normally a task control block.
* The pxOwner parameter effectively creates a two way link between the list
* item and its owner.
*
* @param pxList The list from which the next item owner is to be returned.
*
* \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
* \ingroup LinkedList
*/
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
/* Increment the index to the next item and return the item, ensuring */ \
/* we don't return the marker used at the end of the list. */ \
( pxList )->pxIndex = ( pxList )->pxIndex->pxNext; \
if( ( pxList )->pxIndex == ( xListItem * ) &( ( pxList )->xListEnd ) ) \
{ \
( pxList )->pxIndex = ( pxList )->pxIndex->pxNext; \
} \
pxTCB = ( pxList )->pxIndex->pvOwner
 
 
/*
* Access function to obtain the owner of the first entry in a list. Lists
* are normally sorted in ascending item value order.
*
* This function returns the pxOwner member of the first item in the list.
* The pxOwner parameter of a list item is a pointer to the object that owns
* the list item. In the scheduler this is normally a task control block.
* The pxOwner parameter effectively creates a two way link between the list
* item and its owner.
*
* @param pxList The list from which the owner of the head item is to be
* returned.
*
* \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
* \ingroup LinkedList
*/
#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( pxList->uxNumberOfItems != ( unsigned portBASE_TYPE ) 0 ) ? ( (&( pxList->xListEnd ))->pxNext->pvOwner ) : ( NULL ) )
 
/*
* Check to see if a list item is within a list. The list item maintains a
* "container" pointer that points to the list it is in. All this macro does
* is check to see if the container and the list match.
*
* @param pxList The list we want to know if the list item is within.
* @param pxListItem The list item we want to know if is in the list.
* @return pdTRUE is the list item is in the list, otherwise pdFALSE.
* pointer against
*/
#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) pxList )
 
/*
* Must be called before a list is used! This initialises all the members
* of the list structure and inserts the xListEnd item into the list as a
* marker to the back of the list.
*
* @param pxList Pointer to the list being initialised.
*
* \page vListInitialise vListInitialise
* \ingroup LinkedList
*/
void vListInitialise( xList *pxList );
 
/*
* Must be called before a list item is used. This sets the list container to
* null so the item does not think that it is already contained in a list.
*
* @param pxItem Pointer to the list item being initialised.
*
* \page vListInitialiseItem vListInitialiseItem
* \ingroup LinkedList
*/
void vListInitialiseItem( xListItem *pxItem );
 
/*
* Insert a list item into a list. The item will be inserted into the list in
* a position determined by its item value (descending item value order).
*
* @param pxList The list into which the item is to be inserted.
*
* @param pxNewListItem The item to that is to be placed in the list.
*
* \page vListInsert vListInsert
* \ingroup LinkedList
*/
void vListInsert( xList *pxList, xListItem *pxNewListItem );
 
/*
* Insert a list item into a list. The item will be inserted in a position
* such that it will be the last item within the list returned by multiple
* calls to listGET_OWNER_OF_NEXT_ENTRY.
*
* The list member pvIndex is used to walk through a list. Calling
* listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list.
* Placing an item in a list using vListInsertEnd effectively places the item
* in the list position pointed to by pvIndex. This means that every other
* item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
* the pvIndex parameter again points to the item being inserted.
*
* @param pxList The list into which the item is to be inserted.
*
* @param pxNewListItem The list item to be inserted into the list.
*
* \page vListInsertEnd vListInsertEnd
* \ingroup LinkedList
*/
void vListInsertEnd( xList *pxList, xListItem *pxNewListItem );
 
/*
* Remove an item from a list. The list item has a pointer to the list that
* it is in, so only the list item need be passed into the function.
*
* @param vListRemove The item to be removed. The item will remove itself from
* the list pointed to by it's pxContainer parameter.
*
* \page vListRemove vListRemove
* \ingroup LinkedList
*/
void vListRemove( xListItem *pxItemToRemove );
 
 
 
#endif
 
/trunk/sw/freertos/projdefs.h
0,0 → 1,56
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#ifndef PROJDEFS_H
#define PROJDEFS_H
 
/* Defines to prototype to which task functions must conform. */
typedef void (*pdTASK_CODE)( void * );
 
#define pdTRUE ( 1 )
#define pdFALSE ( 0 )
 
#define pdPASS ( 1 )
#define pdFAIL ( 0 )
#define errQUEUE_EMPTY ( 0 )
#define errQUEUE_FULL ( 0 )
 
/* Error definitions. */
#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
#define errNO_TASK_TO_RUN ( -2 )
#define errQUEUE_BLOCKED ( -4 )
#define errQUEUE_YIELD ( -5 )
 
#endif /* PROJDEFS_H */
 
 
 
/trunk/sw/freertos/FreeRTOSConfig.h
0,0 → 1,73
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
 
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*----------------------------------------------------------*/
 
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned portLONG ) 25000000 )
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 4 )
#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 512 )
#define configMAX_TASK_NAME_LEN ( 4 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 0
 
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
 
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
 
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
 
#endif /* FREERTOS_CONFIG_H */
/trunk/sw/freertos/port.c
0,0 → 1,292
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the MicroBlaze port.
*----------------------------------------------------------*/
 
#include <stdio.h>
 
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
 
/* Standard includes. */
#include <string.h>
 
/* Hardware includes. */
#include "openfire.h"
 
/* Tasks are started with interrupts enabled. */
#define portINITIAL_MSR_STATE ( ( portSTACK_TYPE ) 0x02 )
 
/* Tasks are started with a critical section nesting of 0 - however prior
to the scheduler being commenced we don't want the critical nesting level
to reach zero, so it is initialised to a high value. */
#define portINITIAL_NESTING_VALUE ( 0xff )
 
/* The stack used by the ISR is filled with a known value to assist in
debugging. */
#define portISR_STACK_FILL_VALUE 0x55555555
 
/* Counts the nesting depth of calls to portENTER_CRITICAL(). Each task
maintains it's own count, so this variable is saved as part of the task
context. */
volatile unsigned portBASE_TYPE uxCriticalNesting = portINITIAL_NESTING_VALUE;
 
/* To limit the amount of stack required by each task, this port uses a
separate stack for interrupts. */
unsigned portLONG *pulISRStack;
 
/*-----------------------------------------------------------*/
 
/*
* Sets up the periodic ISR used for the RTOS tick. This uses timer 0, but
* could have alternatively used the watchdog timer or timer 1.
*/
static void prvSetupTimerInterrupt( void );
/*-----------------------------------------------------------*/
 
/*
* Initialise the stack of a task to look exactly as if a call to
* portSAVE_CONTEXT had been made.
*
* See the header file portable.h.
*/
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
extern void *_SDA2_BASE_, *_SDA_BASE_;
const unsigned portLONG ulR2 = ( unsigned portLONG ) &_SDA2_BASE_;
const unsigned portLONG ulR13 = ( unsigned portLONG ) &_SDA_BASE_;
 
/* Place a few bytes of known values on the bottom of the stack.
This is essential for the Microblaze port and these lines must
not be omitted. The parameter value will overwrite the
0x22222222 value during the function prologue. */
*pxTopOfStack = ( portSTACK_TYPE ) 0x11111111;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x22222222;
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x33333333;
pxTopOfStack--;
 
/* First stack an initial value for the critical section nesting. This
is initialised to zero as tasks are started with interrupts enabled. */
*pxTopOfStack = ( portSTACK_TYPE ) 0x00; /* R0. */
 
/* Place an initial value for all the general purpose registers. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) ulR2; /* R2 - small data area. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x03; /* R3. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x04; /* R4. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters;/* R5 contains the function call parameters. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x06; /* R6. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x07; /* R7. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x08; /* R8. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x09; /* R9. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0a; /* R10. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0b; /* R11. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0c; /* R12. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) ulR13; /* R13 - small data read write area. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) pxCode; /* R14. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0f; /* R15. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x10; /* R16. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x11; /* R17. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x12; /* R18. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x13; /* R19. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x14; /* R20. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x15; /* R21. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x16; /* R22. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x17; /* R23. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x18; /* R24. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x19; /* R25. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x1a; /* R26. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x1b; /* R27. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x1c; /* R28. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x1d; /* R29. */
pxTopOfStack--;
*pxTopOfStack = ( portSTACK_TYPE ) 0x1e; /* R30. */
pxTopOfStack--;
 
/* The MSR is stacked between R30 and R31. */
*pxTopOfStack = portINITIAL_MSR_STATE;
pxTopOfStack--;
 
*pxTopOfStack = ( portSTACK_TYPE ) 0x1f; /* R31. */
pxTopOfStack--;
 
/* Return a pointer to the top of the stack we have generated so this can
be stored in the task control block for the task. */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
 
portBASE_TYPE xPortStartScheduler( void )
{
extern void ( __FreeRTOS_interrupt_Handler )( void );
extern void ( vStartFirstTask )( void );
 
/* Setup the FreeRTOS interrupt handler. Code copied from crt0.s. */
asm volatile ( "la r6, r0, __FreeRTOS_interrupt_handler \n\t" \
"sw r6, r1, r0 \n\t" \
"lhu r7, r1, r0 \n\t" \
"shi r7, r0, 0x12 \n\t" \
"shi r6, r0, 0x16 \n\t" );
 
/* Setup the hardware to generate the tick. Interrupts are disabled when
this function is called. */
prvSetupTimerInterrupt();
 
/* Allocate the stack to be used by the interrupt handler. */
pulISRStack = ( unsigned portLONG * ) pvPortMalloc( configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ) );
 
/* Restore the context of the first task that is going to run. */
if( pulISRStack != NULL )
{
/* Fill the ISR stack with a known value to facilitate debugging. */
memset( pulISRStack, portISR_STACK_FILL_VALUE, configMINIMAL_STACK_SIZE * sizeof( portSTACK_TYPE ) );
pulISRStack += ( configMINIMAL_STACK_SIZE - 1 );
 
/* Kick off the first task. */
vStartFirstTask();
}
 
/* Should not get here as the tasks are now running! */
return pdFALSE;
}
/*-----------------------------------------------------------*/
 
void vPortEndScheduler( void )
{
/* Not implemented. */
}
/*-----------------------------------------------------------*/
 
/*
* Manual context switch called by portYIELD or taskYIELD.
*/
void vPortYield( void )
{
extern void VPortYieldASM( void );
 
/* Perform the context switch in a critical section to assure it is
not interrupted by the tick ISR. It is not a problem to do this as
each task maintains it's own interrupt status. */
portENTER_CRITICAL();
/* Jump directly to the yield function to ensure there is no
compiler generated prologue code. */
asm volatile ( "bralid r14, VPortYieldASM \n\t" \
"or r0, r0, r0 \n\t" );
portEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
 
/*
* Hardware initialisation to generate the RTOS tick.
*/
static void prvSetupTimerInterrupt( void )
{
const unsigned portLONG ulCounterValue = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
 
/* configure Timer1 with ulCounterValue and enable timer */
*(unsigned portLONG *) TIMER1_PORT = TIMER1_CONTROL | ulCounterValue;
 
/* enable interrupts for timer1 */
*(unsigned portLONG *) INTERRUPT_ENABLE = INTERRUPT_TIMER1;
}
/*-----------------------------------------------------------*/
 
/*
* The interrupt handler placed in the interrupt vector when the scheduler is
* started. The task context has already been saved when this is called.
* This handler determines the interrupt source and calls the relevant
* peripheral handler.
*/
void vTaskISRHandler( void )
{
/* todo : check which peripheral triggered the interrupt */
/* Increment the RTOS tick - this might cause a task to unblock. */
vTaskIncrementTick();
 
/* Clear the timer interrupt */
/* automatically cleread --> better design? */
 
/* If we are using the preemptive scheduler then we also need to determine
if this tick should cause a context switch. */
#if configUSE_PREEMPTION == 1
vTaskSwitchContext();
#endif
}
/*-----------------------------------------------------------*/
 
void openfire_disable_interrupts(void)
{
asm volatile ( "mfs r5, rmsr \n\t" \
"andi r5, r0, ~0x2 \n\t" \
"mts rmsr, r5 \n\t");
}
 
void openfire_enable_interrupts(void)
{
asm volatile ( "mfs r5, rmsr \n\t" \
"ori r5, r0, 0x2 \n\t" \
"mts rmsr, r5 \n\t");
}
 
/trunk/sw/freertos/queue.c
0,0 → 1,927
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*
Changes from V1.01
 
+ More use of 8bit data types.
+ Function name prefixes changed where the data type returned has changed.
 
Changed from V2.0.0
 
+ Added the queue locking mechanism and make more use of the scheduler
suspension feature to minimise the time interrupts have to be disabled
when accessing a queue.
 
Changed from V2.2.0
 
+ Explicit use of 'signed' qualifier on portCHAR types added.
 
Changes from V3.0.0
 
+ API changes as described on the FreeRTOS.org WEB site.
 
Changes from V3.2.3
 
+ Added the queue functions that can be used from co-routines.
 
Changes from V4.0.5
 
+ Added a loop within xQueueSend() and xQueueReceive() to prevent the
functions exiting when a block time remains and the function has
not completed.
 
Changes from V4.1.2:
 
+ BUG FIX: Removed the call to prvIsQueueEmpty from within xQueueCRReceive
as it exited with interrupts enabled. Thanks Paul Katz.
 
Changes from V4.1.3:
 
+ Modified xQueueSend() and xQueueReceive() to handle the (very unlikely)
case whereby a task unblocking due to a temporal event can remove/send an
item from/to a queue when a higher priority task is still blocked on the
queue. This modification is a result of the SafeRTOS testing.
*/
 
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
 
/*-----------------------------------------------------------
* PUBLIC LIST API documented in list.h
*----------------------------------------------------------*/
 
/* Constants used with the cRxLock and cTxLock structure members. */
#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
#define queueERRONEOUS_UNBLOCK ( -1 )
 
/*
* Definition of the queue used by the scheduler.
* Items are queued by copy, not reference.
*/
typedef struct QueueDefinition
{
signed portCHAR *pcHead; /*< Points to the beginning of the queue storage area. */
signed portCHAR *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
 
signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from. */
 
xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
 
unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
 
signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
} xQUEUE;
/*-----------------------------------------------------------*/
 
/*
* Inside this file xQueueHandle is a pointer to a xQUEUE structure.
* To keep the definition private the API header file defines it as a
* pointer to void.
*/
typedef xQUEUE * xQueueHandle;
 
/*
* Prototypes for public functions are included here so we don't have to
* include the API header file (as it defines xQueueHandle differently). These
* functions are documented in the API header file.
*/
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );
void vQueueDelete( xQueueHandle xQueue );
signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
 
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
#endif
 
/*
* Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
* prevent an ISR from adding or removing items to the queue, but does prevent
* an ISR from removing tasks from the queue event lists. If an ISR finds a
* queue is locked it will instead increment the appropriate queue lock count
* to indicate that a task may require unblocking. When the queue in unlocked
* these lock counts are inspected, and the appropriate action taken.
*/
static void prvUnlockQueue( xQueueHandle pxQueue );
 
/*
* Uses a critical section to determine if there is any data in a queue.
*
* @return pdTRUE if the queue contains no items, otherwise pdFALSE.
*/
static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );
 
/*
* Uses a critical section to determine if there is any space in a queue.
*
* @return pdTRUE if there is no space, otherwise pdFALSE;
*/
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
 
/*
* Macro that copies an item into the queue. This is done by copying the item
* byte for byte, not by reference. Updates the queue state to ensure it's
* integrity after the copy.
*/
#define prvCopyQueueData( pxQueue, pvItemToQueue ) \
{ \
memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); \
++( pxQueue->uxMessagesWaiting ); \
pxQueue->pcWriteTo += pxQueue->uxItemSize; \
if( pxQueue->pcWriteTo >= pxQueue->pcTail ) \
{ \
pxQueue->pcWriteTo = pxQueue->pcHead; \
} \
}
/*-----------------------------------------------------------*/
 
/*
* Macro to mark a queue as locked. Locking a queue prevents an ISR from
* accessing the queue event lists.
*/
#define prvLockQueue( pxQueue ) \
{ \
taskENTER_CRITICAL(); \
++( pxQueue->xRxLock ); \
++( pxQueue->xTxLock ); \
taskEXIT_CRITICAL(); \
}
/*-----------------------------------------------------------*/
 
 
/*-----------------------------------------------------------
* PUBLIC QUEUE MANAGEMENT API documented in queue.h
*----------------------------------------------------------*/
 
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
{
xQUEUE *pxNewQueue;
size_t xQueueSizeInBytes;
 
/* Allocate the new queue structure. */
if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
{
pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
if( pxNewQueue != NULL )
{
/* Create the list of pointers to queue items. The queue is one byte
longer than asked for to make wrap checking easier/faster. */
xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
 
pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );
if( pxNewQueue->pcHead != NULL )
{
/* Initialise the queue members as described above where the
queue type is defined. */
pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
pxNewQueue->uxMessagesWaiting = 0;
pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );
pxNewQueue->uxLength = uxQueueLength;
pxNewQueue->uxItemSize = uxItemSize;
pxNewQueue->xRxLock = queueUNLOCKED;
pxNewQueue->xTxLock = queueUNLOCKED;
 
/* Likewise ensure the event queues start with the correct state. */
vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
 
return pxNewQueue;
}
else
{
vPortFree( pxNewQueue );
}
}
}
 
/* Will only reach here if we could not allocate enough memory or no memory
was required. */
return NULL;
}
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn = pdPASS;
xTimeOutType xTimeOut;
 
/* Make sure other tasks do not access the queue. */
vTaskSuspendAll();
 
/* Capture the current time status for future reference. */
vTaskSetTimeOutState( &xTimeOut );
 
/* It is important that this is the only thread/ISR that modifies the
ready or delayed lists until xTaskResumeAll() is called. Places where
the ready/delayed lists are modified include:
 
+ vTaskDelay() - Nothing can call vTaskDelay as the scheduler is
suspended, vTaskDelay() cannot be called from an ISR.
+ vTaskPrioritySet() - Has a critical section around the access.
+ vTaskSwitchContext() - This will not get executed while the scheduler
is suspended.
+ prvCheckDelayedTasks() - This will not get executed while the
scheduler is suspended.
+ xTaskCreate() - Has a critical section around the access.
+ vTaskResume() - Has a critical section around the access.
+ xTaskResumeAll() - Has a critical section around the access.
+ xTaskRemoveFromEventList - Checks to see if the scheduler is
suspended. If so then the TCB being removed from the event is
removed from the event and added to the xPendingReadyList.
*/
 
/* Make sure interrupts do not access the queue event list. */
prvLockQueue( pxQueue );
 
/* It is important that interrupts to not access the event list of the
queue being modified here. Places where the event list is modified
include:
 
+ xQueueSendFromISR(). This checks the lock on the queue to see if
it has access. If the queue is locked then the Tx lock count is
incremented to signify that a task waiting for data can be made ready
once the queue lock is removed. If the queue is not locked then
a task can be moved from the event list, but will not be removed
from the delayed list or placed in the ready list until the scheduler
is unlocked.
 
+ xQueueReceiveFromISR(). As per xQueueSendFromISR().
*/
/* If the queue is already full we may have to block. */
do
{
if( prvIsQueueFull( pxQueue ) )
{
/* The queue is full - do we want to block or just leave without
posting? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* We are going to place ourselves on the xTasksWaitingToSend event
list, and will get woken should the delay expire, or space become
available on the queue.
As detailed above we do not require mutual exclusion on the event
list as nothing else can modify it or the ready lists while we
have the scheduler suspended and queue locked.
It is possible that an ISR has removed data from the queue since we
checked if any was available. If this is the case then the data
will have been copied from the queue, and the queue variables
updated, but the event list will not yet have been checked to see if
anything is waiting as the queue is locked. */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
/* Force a context switch now as we are blocked. We can do
this from within a critical section as the task we are
switching to has its own context. When we return here (i.e. we
unblock) we will leave the critical section as normal.
It is possible that an ISR has caused an event on an unrelated and
unlocked queue. If this was the case then the event list for that
queue will have been updated but the ready lists left unchanged -
instead the readied task will have been added to the pending ready
list. */
taskENTER_CRITICAL();
{
/* We can safely unlock the queue and scheduler here as
interrupts are disabled. We must not yield with anything
locked, but we can yield from within a critical section.
Tasks that have been placed on the pending ready list cannot
be tasks that are waiting for events on this queue. See
in comment xTaskRemoveFromEventList(). */
prvUnlockQueue( pxQueue );
/* Resuming the scheduler may cause a yield. If so then there
is no point yielding again here. */
if( !xTaskResumeAll() )
{
taskYIELD();
}
 
/* We want to check to see if the queue is still full
before leaving the critical section. This is to prevent
this task placing an item into the queue due to an
interrupt making space on the queue between critical
sections (when there might be a higher priority task
blocked on the queue that cannot run yet because the
scheduler gets suspended). */
if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
{
/* We unblocked but there is no space in the queue,
we probably timed out. */
xReturn = errQUEUE_FULL;
}
/* Before leaving the critical section we have to ensure
exclusive access again. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
}
taskEXIT_CRITICAL();
}
}
/* If xReturn is errQUEUE_FULL then we unblocked when the queue
was still full. Don't check it again now as it is possible that
an interrupt has removed an item from the queue since we left the
critical section and we don't want to write to the queue in case
there is a task of higher priority blocked waiting for space to
be available on the queue. If this is the case the higher priority
task will execute when the scheduler is unsupended. */
if( xReturn != errQUEUE_FULL )
{
/* When we are here it is possible that we unblocked as space became
available on the queue. It is also possible that an ISR posted to the
queue since we left the critical section, so it may be that again there
is no space. This would only happen if a task and ISR post onto the
same queue. */
taskENTER_CRITICAL();
{
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
prvCopyQueueData( pxQueue, pvItemToQueue );
xReturn = pdPASS;
/* Update the TxLock count so prvUnlockQueue knows to check for
tasks waiting for data to become available in the queue. */
++( pxQueue->xTxLock );
}
else
{
xReturn = errQUEUE_FULL;
}
}
taskEXIT_CRITICAL();
}
 
if( xReturn == errQUEUE_FULL )
{
if( xTicksToWait > 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
xReturn = queueERRONEOUS_UNBLOCK;
}
}
}
}
while( xReturn == queueERRONEOUS_UNBLOCK );
 
prvUnlockQueue( pxQueue );
xTaskResumeAll();
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )
{
/* Similar to xQueueSend, except we don't block if there is no room in the
queue. Also we don't directly wake a task that was blocked on a queue
read, instead we return a flag to say whether a context switch is required
or not (i.e. has a task with a higher priority than us been woken by this
post). */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
prvCopyQueueData( pxQueue, pvItemToQueue );
 
/* If the queue is locked we do not alter the event list. This will
be done when the queue is unlocked later. */
if( pxQueue->xTxLock == queueUNLOCKED )
{
/* We only want to wake one task per ISR, so check that a task has
not already been woken. */
if( !xTaskPreviouslyWoken )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
context switch is required. */
return pdTRUE;
}
}
}
}
else
{
/* Increment the lock count so the task that unlocks the queue
knows that data was posted while it was locked. */
++( pxQueue->xTxLock );
}
}
 
return xTaskPreviouslyWoken;
}
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn = pdTRUE;
xTimeOutType xTimeOut;
 
/* This function is very similar to xQueueSend(). See comments within
xQueueSend() for a more detailed explanation.
 
Make sure other tasks do not access the queue. */
vTaskSuspendAll();
 
/* Capture the current time status for future reference. */
vTaskSetTimeOutState( &xTimeOut );
 
/* Make sure interrupts do not access the queue. */
prvLockQueue( pxQueue );
 
do
{
/* If there are no messages in the queue we may have to block. */
if( prvIsQueueEmpty( pxQueue ) )
{
/* There are no messages in the queue, do we want to block or just
leave with nothing? */
if( xTicksToWait > ( portTickType ) 0 )
{
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
taskENTER_CRITICAL();
{
prvUnlockQueue( pxQueue );
if( !xTaskResumeAll() )
{
taskYIELD();
}
 
if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
{
/* We unblocked but the queue is empty. We probably
timed out. */
xReturn = errQUEUE_EMPTY;
}
vTaskSuspendAll();
prvLockQueue( pxQueue );
}
taskEXIT_CRITICAL();
}
}
if( xReturn != errQUEUE_EMPTY )
{
taskENTER_CRITICAL();
{
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
/* Increment the lock count so prvUnlockQueue knows to check for
tasks waiting for space to become available on the queue. */
++( pxQueue->xRxLock );
xReturn = pdPASS;
}
else
{
xReturn = errQUEUE_EMPTY;
}
}
taskEXIT_CRITICAL();
}
 
if( xReturn == errQUEUE_EMPTY )
{
if( xTicksToWait > 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
xReturn = queueERRONEOUS_UNBLOCK;
}
}
}
} while( xReturn == queueERRONEOUS_UNBLOCK );
 
/* We no longer require exclusive access to the queue. */
prvUnlockQueue( pxQueue );
xTaskResumeAll();
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )
{
signed portBASE_TYPE xReturn;
 
/* We cannot block from an ISR, so check there is data available. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
/* Copy the data from the queue. */
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
 
/* If the queue is locked we will not modify the event list. Instead
we update the lock count so the task that unlocks the queue will know
that an ISR has removed data while the queue was locked. */
if( pxQueue->xRxLock == queueUNLOCKED )
{
/* We only want to wake one task per ISR, so check that a task has
not already been woken. */
if( !( *pxTaskWoken ) )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
/* The task waiting has a higher priority than us so
force a context switch. */
*pxTaskWoken = pdTRUE;
}
}
}
}
else
{
/* Increment the lock count so the task that unlocks the queue
knows that data was removed while it was locked. */
++( pxQueue->xRxLock );
}
 
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue )
{
unsigned portBASE_TYPE uxReturn;
 
taskENTER_CRITICAL();
uxReturn = pxQueue->uxMessagesWaiting;
taskEXIT_CRITICAL();
 
return uxReturn;
}
/*-----------------------------------------------------------*/
 
void vQueueDelete( xQueueHandle pxQueue )
{
vPortFree( pxQueue->pcHead );
vPortFree( pxQueue );
}
/*-----------------------------------------------------------*/
 
static void prvUnlockQueue( xQueueHandle pxQueue )
{
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
 
/* The lock counts contains the number of extra data items placed or
removed from the queue while the queue was locked. When a queue is
locked items can be added or removed, but the event lists cannot be
updated. */
taskENTER_CRITICAL();
{
--( pxQueue->xTxLock );
 
/* See if data was added to the queue while it was locked. */
if( pxQueue->xTxLock > queueUNLOCKED )
{
pxQueue->xTxLock = queueUNLOCKED;
 
/* Data was posted while the queue was locked. Are any tasks
blocked waiting for data to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
/* Tasks that are removed from the event list will get added to
the pending ready list as the scheduler is still suspended. */
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
context switch is required. */
vTaskMissedYield();
}
}
}
}
taskEXIT_CRITICAL();
 
/* Do the same for the Rx lock. */
taskENTER_CRITICAL();
{
--( pxQueue->xRxLock );
 
if( pxQueue->xRxLock > queueUNLOCKED )
{
pxQueue->xRxLock = queueUNLOCKED;
 
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
vTaskMissedYield();
}
}
}
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
 
static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
 
taskENTER_CRITICAL();
xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
taskEXIT_CRITICAL();
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
 
taskENTER_CRITICAL();
xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
taskEXIT_CRITICAL();
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
/* If the queue is already full we may have to block. A critical section
is required to prevent an interrupt removing something from the queue
between the check to see if the queue is full and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
if( prvIsQueueFull( pxQueue ) )
{
/* The queue is full - do we want to block or just leave without
posting? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* As this is called from a coroutine we cannot block directly, but
return indicating that we need to block. */
vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
portENABLE_INTERRUPTS();
return errQUEUE_BLOCKED;
}
else
{
portENABLE_INTERRUPTS();
return errQUEUE_FULL;
}
}
}
portENABLE_INTERRUPTS();
portNOP();
 
portDISABLE_INTERRUPTS();
{
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
prvCopyQueueData( pxQueue, pvItemToQueue );
xReturn = pdPASS;
 
/* Were any co-routines waiting for data to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
/* In this instance the co-routine could be placed directly
into the ready list as we are within a critical section.
Instead the same pending ready list mechansim is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The co-routine waiting has a higher priority so record
that a yield might be appropriate. */
xReturn = errQUEUE_YIELD;
}
}
}
else
{
xReturn = errQUEUE_FULL;
}
}
portENABLE_INTERRUPTS();
 
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
 
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
 
/* If the queue is already empty we may have to block. A critical section
is required to prevent an interrupt adding something to the queue
between the check to see if the queue is empty and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
{
/* There are no messages in the queue, do we want to block or just
leave with nothing? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* As this is a co-routine we cannot block directly, but return
indicating that we need to block. */
vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
portENABLE_INTERRUPTS();
return errQUEUE_BLOCKED;
}
else
{
portENABLE_INTERRUPTS();
return errQUEUE_FULL;
}
}
}
portENABLE_INTERRUPTS();
 
portNOP();
 
portDISABLE_INTERRUPTS();
{
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
/* Data is available from the queue. */
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
 
xReturn = pdPASS;
 
/* Were any co-routines waiting for space to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
/* In this instance the co-routine could be placed directly
into the ready list as we are within a critical section.
Instead the same pending ready list mechansim is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
xReturn = errQUEUE_YIELD;
}
}
}
else
{
xReturn = pdFAIL;
}
}
portENABLE_INTERRUPTS();
 
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
 
 
 
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
{
/* Cannot block within an ISR so if there is no space on the queue then
exit without doing anything. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
prvCopyQueueData( pxQueue, pvItemToQueue );
 
/* We only want to wake one co-routine per ISR, so check that a
co-routine has not already been woken. */
if( !xCoRoutinePreviouslyWoken )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
return pdTRUE;
}
}
}
}
 
return xCoRoutinePreviouslyWoken;
}
#endif
/*-----------------------------------------------------------*/
 
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
{
signed portBASE_TYPE xReturn;
 
/* We cannot block from an ISR, so check there is data available. If
not then just leave without doing anything. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
/* Copy the data from the queue. */
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
 
if( !( *pxCoRoutineWoken ) )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
*pxCoRoutineWoken = pdTRUE;
}
}
}
 
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
 
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
 
/trunk/sw/freertos/tasks.c
0,0 → 1,1860
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
/*
Changes from V1.00:
+ Call to portRESTORE_CONTEXT has been removed. The first context
switch is now performed within sPortStartScheduler().
 
Changes from V1.01:
 
+ More use of 8bit data types.
+ Function name prefixes changed where the data type returned has changed.
+ configUSE_TRACE_FACILITY is no longer defined by default.
 
Changes from V1.2.0
 
+ Introduced ucTopReadyPriority. This tracks the highest priority ready
queue that contains a valid TCB and thus makes the context switch
slightly faster.
 
+ prvAddTaskToReadyQueue() has been made a macro.
 
Changes from V1.2.6
 
+ Added conditional compilation directives.
+ Extended API.
+ Rearranged function order.
+ Creating a task now causes a context switch if the task being created
has a higher priority than the calling task - assuming the kernel is
running.
+ vTaskDelete() now only causes a context switch if the calling task is
the task being deleted.
 
Changes from V2.0.0
 
+ Allow the type of the tick count to be 16 or 32 bits.
+ Introduce xPendingReadyList feature to allow the time interrupts have to
be disabled to be minimised.
+ Remove the #if( INCLUDE_vTaskSuspendAll ) statements. vTaskSuspendAll()
is now always included as it is used by the scheduler itself.
 
Changes from V2.1.0
 
+ Bug fix - pxCurrentTCB is now initialised before the call to
prvInitializeTaskLists(). Previously pxCurrentTCB could be accessed
while null.
 
Changed from V2.1.1
 
+ Change to where lStackSize is declared within sTaskCreate() to prevent
compiler warnings with 8051 port.
 
Changes from V2.2.0
 
+ Explicit use of 'signed' qualifier on portCHAR types added.
+ Changed odd calculation of initial pxTopOfStack value when
portSTACK_GROWTH < 0.
+ Removed pcVersionNumber definition.
 
Changes from V2.5.3
 
+ cTaskResumeAll() modified to ensure it can be called prior to the task
lists being initialised.
 
Changes from V2.5.5
 
+ Added API function vTaskDelayUntil().
+ Added INCLUDE_vTaskDelay conditional compilation.
 
Changes from V2.6.0
 
+ Updated the vWriteTraceToBuffer macro to always be 4 byte aligned so it
can be used on ARM architectures.
+ tskMAX_TASK_NAME_LEN definition replaced with the port specific
configMAX_TASK_NAME_LEN definition.
+ Removed the call to strcpy when copying across the task name into the
TCB.
+ Added ucTasksDeleted variable to prevent vTaskSuspendAll() being called
too often in the idle task.
 
Changes between V3.0.0 and V2.6.1
 
+ When resuming the scheduler a yield is performed if either a tick has
been missed, or a task is moved from the pending ready list into a ready
list. Previously a yield was not performed on this second condition.
+ Introduced the type portBASE_TYPE. This necessitates several API
changes.
+ Removed the sUsingPreemption variable. The constant defined in
portmacro.h is now used directly.
+ The idle task can now include an optional hook function - and no longer
completes its time slice if other tasks with equal priority to it are
ready to run.
+ See the FreeRTOS.org documentation for more information on V2.x.x to
V3.x.x modifications.
 
Changes from V3.1.1
 
+ Modified vTaskPrioritySet() and vTaskResume() to allow these functions to
be called while the scheduler is suspended.
+ Corrected the task ordering within event lists.
 
Changes from V3.2.0
 
+ Added function xTaskGetCurrentTaskHandle().
 
Changes from V3.2.4
 
+ Changed the volatile declarations on some variables to reflect the
changes to the list definitions.
+ Changed the order of the TCB definition so there is commonality between
the task control block and a co-routine control block.
+ Allow the scheduler to be started even if no tasks other than the idle
task has been created. This allows co-routines to run even when no tasks
have been created.
+ The need for a context switch is now signalled if a task woken by an
event has a priority greater or equal to the currently running task.
Previously this was only greater than.
 
Changes from V4.0.0
 
+ Added the xMissedYield handling.
 
Changes from V4.0.1
 
+ The function vTaskList() now suspends the scheduler rather than disabling
interrupts during the creation of the task list.
+ Allow a task to delete itself by passing in its own handle. Previously
this could only be done by passing in NULL.
+ The tick hook function is now called only within a tick isr. Previously
it was also called when the tick function was called during the scheduler
unlocking process.
 
Changes from V4.0.3
 
+ Extra checks have been placed in vTaskPrioritySet() to avoid unnecessary
yields.
 
Changed from V4.0.4
 
+ Bug fix: The 'value' of the event list item is updated when the priority
of a task is changed. Previously only the priority of the TCB itself was
changed.
+ When resuming a task a check is first made to see if the task is actually
suspended.
+ vTaskPrioritySet() and vTaskResume() no longer use the event list item.
This has not been necessary since V4.0.1 when the xMissedYield handling
was added.
+ Implement xTaskResumeFromISR().
 
Changes from V4.0.5
 
+ Added utility functions and xOverflowCount variable to facilitate the
queue.c changes.
 
Changes from V4.1.2
+ Tasks that block on events with a timeout of portMAX_DELAY are now
blocked indefinitely if configINCLUDE_vTaskSuspend is defined.
Previously portMAX_DELAY was just the longest block time possible.
 
Changes from V4.1.3
 
+ Very small change made to xTaskCheckForTimeout() as a result of the
SafeRTOS testing. This corrects the case where the function can return an
invalid value - but only in an extremely unlikely scenario.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#include "FreeRTOS.h"
#include "task.h"
 
/*
* Macro to define the amount of stack available to the idle task.
*/
#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
 
 
/*
* Default a definitions for backwards compatibility with old
* portmacro.h files.
*/
#ifndef configMAX_TASK_NAME_LEN
#define configMAX_TASK_NAME_LEN 16
#endif
 
#ifndef INCLUDE_xTaskGetCurrentTaskHandle
#define INCLUDE_xTaskGetCurrentTaskHandle 0
#endif
 
#ifndef configIDLE_SHOULD_YIELD
#define configIDLE_SHOULD_YIELD 1
#endif
 
#if configMAX_TASK_NAME_LEN < 1
#undef configMAX_TASK_NAME_LEN
#define configMAX_TASK_NAME_LEN 1
#endif
 
#ifndef INCLUDE_xTaskResumeFromISR
#define INCLUDE_xTaskResumeFromISR 1
#endif
 
/*
* Task control block. A task control block (TCB) is allocated to each task,
* and stores the context of the task.
*/
typedef struct tskTaskControlBlock
{
volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
unsigned portSHORT usStackDepth; /*< Total depth of the stack (when empty). This is defined as the number of variables the stack can hold, not the number of bytes. */
} tskTCB;
 
/*lint -e956 */
 
tskTCB * volatile pxCurrentTCB = NULL;
 
/* Lists for ready and blocked tasks. --------------------*/
 
static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
static xList xDelayedTaskList1; /*< Delayed tasks. */
static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
 
#if ( INCLUDE_vTaskDelete == 1 )
 
static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
 
#endif
 
#if ( INCLUDE_vTaskSuspend == 1 )
 
static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
 
#endif
 
/* File private variables. --------------------------------*/
static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
static volatile portTickType xTickCount = ( portTickType ) 0;
static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
/* Debugging and trace facilities private variables and macros. ------------*/
 
/*
* The value used to fill the stack of a task when the task is created. This
* is used purely for checking the high water mark for tasks.
*/
#define tskSTACK_FILL_BYTE ( 0xa5 )
 
/*
* Macros used by vListTask to indicate which state a task is in.
*/
#define tskBLOCKED_CHAR ( ( signed portCHAR ) 'B' )
#define tskREADY_CHAR ( ( signed portCHAR ) 'R' )
#define tskDELETED_CHAR ( ( signed portCHAR ) 'D' )
#define tskSUSPENDED_CHAR ( ( signed portCHAR ) 'S' )
 
/*
* Macros and private variables used by the trace facility.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
 
#define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
static volatile signed portCHAR * volatile pcTraceBuffer;
static signed portCHAR *pcTraceBufferStart;
static signed portCHAR *pcTraceBufferEnd;
static signed portBASE_TYPE xTracing = pdFALSE;
 
#endif
 
/*
* Macro that writes a trace of scheduler activity to a buffer. This trace
* shows which task is running when and is very useful as a debugging tool.
* As this macro is called each context switch it is a good idea to undefine
* it if not using the facility.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
 
#define vWriteTraceToBuffer() \
{ \
if( xTracing ) \
{ \
static unsigned portBASE_TYPE uxPreviousTask = 255; \
\
if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
{ \
if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
{ \
uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
*( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount; \
pcTraceBuffer += sizeof( unsigned portLONG ); \
*( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask; \
pcTraceBuffer += sizeof( unsigned portLONG ); \
} \
else \
{ \
xTracing = pdFALSE; \
} \
} \
} \
}
 
#else
 
#define vWriteTraceToBuffer()
 
#endif
 
 
/*
* Place the task represented by pxTCB into the appropriate ready queue for
* the task. It is inserted at the end of the list. One quirk of this is
* that if the task being inserted is at the same priority as the currently
* executing task, then it will only be rescheduled after the currently
* executing task has been rescheduled.
*/
#define prvAddTaskToReadyQueue( pxTCB ) \
{ \
if( pxTCB->uxPriority > uxTopReadyPriority ) \
{ \
uxTopReadyPriority = pxTCB->uxPriority; \
} \
vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
}
 
/*
* Macro that looks at the list of tasks that are currently delayed to see if
* any require waking.
*
* Tasks are stored in the queue in the order of their wake time - meaning
* once one tasks has been found whose timer has not expired we need not look
* any further down the list.
*/
#define prvCheckDelayedTasks() \
{ \
register tskTCB *pxTCB; \
\
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
{ \
if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
{ \
break; \
} \
vListRemove( &( pxTCB->xGenericListItem ) ); \
/* Is the task waiting on an event also? */ \
if( pxTCB->xEventListItem.pvContainer ) \
{ \
vListRemove( &( pxTCB->xEventListItem ) ); \
} \
prvAddTaskToReadyQueue( pxTCB ); \
} \
}
 
/*
* Several functions take an xTaskHandle parameter that can optionally be NULL,
* where NULL is used to indicate that the handle of the currently executing
* task should be used in place of the parameter. This macro simply checks to
* see if the parameter is NULL and returns a pointer to the appropriate TCB.
*/
#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
 
 
/* File private functions. --------------------------------*/
 
/*
* Utility to ready a TCB for a given task. Mainly just copies the parameters
* into the TCB structure.
*/
static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
 
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first task.
*/
static void prvInitialiseTaskLists( void );
 
/*
* The idle task, which as all tasks is implemented as a never ending loop.
* The idle task is automatically created and added to the ready lists upon
* creation of the first user task.
*
* The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
* language extensions. The equivalent prototype for this function is:
*
* void prvIdleTask( void *pvParameters );
*
*/
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
 
/*
* Utility to free all memory allocated by the scheduler to hold a TCB,
* including the stack pointed to by the TCB.
*
* This does not free memory allocated by the task itself (i.e. memory
* allocated by calls to pvPortMalloc from within the tasks application code).
*/
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
static void prvDeleteTCB( tskTCB *pxTCB );
#endif
 
/*
* Used only by the idle task. This checks to see if anything has been placed
* in the list of tasks waiting to be deleted. If so the task is cleaned up
* and its TCB deleted.
*/
static void prvCheckTasksWaitingTermination( void );
 
/*
* Allocates memory from the heap for a TCB and associated stack. Checks the
* allocation was successful.
*/
static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
 
/*
* Called from vTaskList. vListTasks details all the tasks currently under
* control of the scheduler. The tasks may be in one of a number of lists.
* prvListTaskWithinSingleList accepts a list and details the tasks from
* within just that list.
*
* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
* NORMAL APPLICATION CODE.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
 
static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
 
#endif
 
/*
* When a task is created, the stack of the task is filled with a known value.
* This function determines the 'high water mark' of the task stack by
* determining how much of the stack remains at the original preset value.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
 
unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte );
 
#endif
 
/*lint +e956 */
 
 
 
 
 
/*-----------------------------------------------------------
* TASK CREATION API documented in task.h
*----------------------------------------------------------*/
 
signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )
{
signed portBASE_TYPE xReturn;
tskTCB * pxNewTCB;
static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
 
/* Allocate the memory required by the TCB and stack for the new task.
checking that the allocation was successful. */
pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
 
if( pxNewTCB != NULL )
{
portSTACK_TYPE *pxTopOfStack;
 
/* Setup the newly allocated TCB with the initial state of the task. */
prvInitialiseTCBVariables( pxNewTCB, usStackDepth, pcName, uxPriority );
 
/* Calculate the top of stack address. This depends on whether the
stack grows from high memory to low (as per the 80x86) or visa versa.
portSTACK_GROWTH is used to make the result positive or negative as
required by the port. */
#if portSTACK_GROWTH < 0
{
pxTopOfStack = pxNewTCB->pxStack + ( pxNewTCB->usStackDepth - 1 );
}
#else
{
pxTopOfStack = pxNewTCB->pxStack;
}
#endif
 
/* Initialize the TCB stack to look as if the task was already running,
but had been interrupted by the scheduler. The return address is set
to the start of the task function. Once the stack has been initialised
the top of stack variable is updated. */
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );
 
/* We are going to manipulate the task queues to add this task to a
ready list, so must make sure no interrupts occur. */
portENTER_CRITICAL();
{
uxCurrentNumberOfTasks++;
if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
{
/* As this is the first task it must also be the current task. */
pxCurrentTCB = pxNewTCB;
 
/* This is the first task to be created so do the preliminary
initialisation required. We will not recover if this call
fails, but we will report the failure. */
prvInitialiseTaskLists();
}
else
{
/* If the scheduler is not already running, make this task the
current task if it is the highest priority task to be created
so far. */
if( xSchedulerRunning == pdFALSE )
{
if( pxCurrentTCB->uxPriority <= uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
}
}
 
/* Remember the top priority to make context switching faster. Use
the priority in pxNewTCB as this has been capped to a valid value. */
if( pxNewTCB->uxPriority > uxTopUsedPriority )
{
uxTopUsedPriority = pxNewTCB->uxPriority;
}
 
/* Add a counter into the TCB for tracing only. */
pxNewTCB->uxTCBNumber = uxTaskNumber;
uxTaskNumber++;
 
prvAddTaskToReadyQueue( pxNewTCB );
 
xReturn = pdPASS;
}
portEXIT_CRITICAL();
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
 
if( xReturn == pdPASS )
{
if( ( void * ) pxCreatedTask != NULL )
{
/* Pass the TCB out - in an anonymous way. The calling function/
task can use this as a handle to delete the task later if
required.*/
*pxCreatedTask = ( xTaskHandle ) pxNewTCB;
}
 
if( xSchedulerRunning != pdFALSE )
{
/* If the created task is of a higher priority than the current task
then it should run now. */
if( pxCurrentTCB->uxPriority < uxPriority )
{
taskYIELD();
}
}
}
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_vTaskDelete == 1 )
 
void vTaskDelete( xTaskHandle pxTaskToDelete )
{
tskTCB *pxTCB;
 
taskENTER_CRITICAL();
{
/* Ensure a yield is performed if the current task is being
deleted. */
if( pxTaskToDelete == pxCurrentTCB )
{
pxTaskToDelete = NULL;
}
 
/* If null is passed in here then we are deleting ourselves. */
pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
 
/* Remove task from the ready list and place in the termination list.
This will stop the task from be scheduled. The idle task will check
the termination list and free up any memory allocated by the
scheduler for the TCB and stack. */
vListRemove( &( pxTCB->xGenericListItem ) );
 
/* Is the task waiting on an event also? */
if( pxTCB->xEventListItem.pvContainer )
{
vListRemove( &( pxTCB->xEventListItem ) );
}
 
vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
 
/* Increment the ucTasksDeleted variable so the idle task knows
there is a task that has been deleted and that it should therefore
check the xTasksWaitingTermination list. */
++uxTasksDeleted;
}
taskEXIT_CRITICAL();
 
/* Force a reschedule if we have just deleted the current task. */
if( xSchedulerRunning != pdFALSE )
{
if( ( void * ) pxTaskToDelete == NULL )
{
taskYIELD();
}
}
}
 
#endif
 
 
 
 
 
 
/*-----------------------------------------------------------
* TASK CONTROL API documented in task.h
*----------------------------------------------------------*/
 
#if ( INCLUDE_vTaskDelayUntil == 1 )
 
void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement )
{
portTickType xTimeToWake;
portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
 
vTaskSuspendAll();
{
/* Generate the tick time at which the task wants to wake. */
xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
 
if( xTickCount < *pxPreviousWakeTime )
{
/* The tick count has overflowed since this function was
lasted called. In this case the only time we should ever
actually delay is if the wake time has also overflowed,
and the wake time is greater than the tick time. When this
is the case it is as if neither time had overflowed. */
if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
{
xShouldDelay = pdTRUE;
}
}
else
{
/* The tick time has not overflowed. In this case we will
delay if either the wake time has overflowed, and/or the
tick time is less than the wake time. */
if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
{
xShouldDelay = pdTRUE;
}
}
 
/* Update the wake time ready for the next call. */
*pxPreviousWakeTime = xTimeToWake;
 
if( xShouldDelay )
{
/* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for
both lists. */
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
 
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
 
if( xTimeToWake < xTickCount )
{
/* Wake time has overflowed. Place this item in the
overflow list. */
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the
current block list. */
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
}
}
xAlreadyYielded = xTaskResumeAll();
 
/* Force a reschedule if xTaskResumeAll has not already done so, we may
have put ourselves to sleep. */
if( !xAlreadyYielded )
{
taskYIELD();
}
}
#endif
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_vTaskDelay == 1 )
 
void vTaskDelay( portTickType xTicksToDelay )
{
portTickType xTimeToWake;
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
 
/* A delay time of zero just forces a reschedule. */
if( xTicksToDelay > ( portTickType ) 0 )
{
vTaskSuspendAll();
{
/* A task that is removed from the event list while the
scheduler is suspended will not get placed in the ready
list or removed from the blocked list until the scheduler
is resumed.
This task cannot be in an event list as it is the currently
executing task. */
 
/* Calculate the time to wake - this may overflow but this is
not a problem. */
xTimeToWake = xTickCount + xTicksToDelay;
 
/* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for
both lists. */
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
 
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
 
if( xTimeToWake < xTickCount )
{
/* Wake time has overflowed. Place this item in the
overflow list. */
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the
current block list. */
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
}
xAlreadyYielded = xTaskResumeAll();
}
/* Force a reschedule if xTaskResumeAll has not already done so, we may
have put ourselves to sleep. */
if( !xAlreadyYielded )
{
taskYIELD();
}
}
#endif
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_uxTaskPriorityGet == 1 )
 
unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
{
tskTCB *pxTCB;
unsigned portBASE_TYPE uxReturn;
 
taskENTER_CRITICAL();
{
/* If null is passed in here then we are changing the
priority of the calling function. */
pxTCB = prvGetTCBFromHandle( pxTask );
uxReturn = pxTCB->uxPriority;
}
taskEXIT_CRITICAL();
 
return uxReturn;
}
 
#endif
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_vTaskPrioritySet == 1 )
 
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
{
tskTCB *pxTCB;
unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
 
/* Ensure the new priority is valid. */
if( uxNewPriority >= configMAX_PRIORITIES )
{
uxNewPriority = configMAX_PRIORITIES - 1;
}
 
taskENTER_CRITICAL();
{
/* If null is passed in here then we are changing the
priority of the calling function. */
pxTCB = prvGetTCBFromHandle( pxTask );
uxCurrentPriority = pxTCB->uxPriority;
 
if( uxCurrentPriority != uxNewPriority )
{
/* The priority change may have readied a task of higher
priority than the calling task. */
if( uxNewPriority > pxCurrentTCB->uxPriority )
{
if( pxTask != NULL )
{
/* The priority of another task is being raised. If we
were raising the priority of the currently running task
there would be no need to switch as it must have already
been the highest priority task. */
xYieldRequired = pdTRUE;
}
}
else if( pxTask == NULL )
{
/* Setting our own priority down means there may now be another
task of higher priority that is ready to execute. */
xYieldRequired = pdTRUE;
}
pxTCB->uxPriority = uxNewPriority;
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxNewPriority );
 
/* If the task is in the blocked or suspended list we need do
nothing more than change it's priority variable. However, if
the task is in a ready list it needs to be removed and placed
in the queue appropriate to its new priority. */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
{
/* The task is currently in its ready list - remove before adding
it to it's new ready list. As we are in a critical section we
can do this even if the scheduler is suspended. */
vListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB );
}
if( xYieldRequired == pdTRUE )
{
taskYIELD();
}
}
}
taskEXIT_CRITICAL();
}
 
#endif
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_vTaskSuspend == 1 )
 
void vTaskSuspend( xTaskHandle pxTaskToSuspend )
{
tskTCB *pxTCB;
 
taskENTER_CRITICAL();
{
/* Ensure a yield is performed if the current task is being
suspended. */
if( pxTaskToSuspend == pxCurrentTCB )
{
pxTaskToSuspend = NULL;
}
 
/* If null is passed in here then we are suspending ourselves. */
pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
 
/* Remove task from the ready/delayed list and place in the suspended list. */
vListRemove( &( pxTCB->xGenericListItem ) );
 
/* Is the task waiting on an event also? */
if( pxTCB->xEventListItem.pvContainer )
{
vListRemove( &( pxTCB->xEventListItem ) );
}
 
vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
}
taskEXIT_CRITICAL();
 
/* We may have just suspended the current task. */
if( ( void * ) pxTaskToSuspend == NULL )
{
taskYIELD();
}
}
 
#endif
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_vTaskSuspend == 1 )
 
void vTaskResume( xTaskHandle pxTaskToResume )
{
tskTCB *pxTCB;
 
/* Remove the task from whichever list it is currently in, and place
it in the ready list. */
pxTCB = ( tskTCB * ) pxTaskToResume;
 
/* The parameter cannot be NULL as it is impossible to resume the
currently executing task. */
if( pxTCB != NULL )
{
taskENTER_CRITICAL();
{
/* Is the task we are attempting to resume actually suspended? */
if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
{
/* Has the task already been resumed from within an ISR? */
if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
{
/* As we are in a critical section we can access the ready
lists even if the scheduler is suspended. */
vListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB );
 
/* We may have just resumed a higher priority task. */
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* This yield may not cause the task just resumed to run, but
will leave the lists in the correct state for the next yield. */
taskYIELD();
}
}
}
}
taskEXIT_CRITICAL();
}
}
 
#endif
 
/*-----------------------------------------------------------*/
 
#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
 
portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
{
portBASE_TYPE xYieldRequired = pdFALSE;
tskTCB *pxTCB;
 
pxTCB = ( tskTCB * ) pxTaskToResume;
 
/* Is the task we are attempting to resume actually suspended? */
if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
{
/* Has the task already been resumed from within an ISR? */
if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
{
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
{
xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
vListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB );
}
else
{
/* We cannot access the delayed or ready lists, so will hold this
task pending until the scheduler is resumed, at which point a
yield will be preformed if necessary. */
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
}
}
}
 
return xYieldRequired;
}
 
#endif
 
 
 
 
/*-----------------------------------------------------------
* PUBLIC SCHEDULER CONTROL documented in task.h
*----------------------------------------------------------*/
 
 
void vTaskStartScheduler( void )
{
portBASE_TYPE xReturn;
 
/* Add the idle task at the lowest priority. */
xReturn = xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
 
if( xReturn == pdPASS )
{
/* Interrupts are turned off here, to ensure a tick does not occur
before or during the call to xPortStartScheduler(). The stacks of
the created tasks contain a status word with interrupts switched on
so interrupts will automatically get re-enabled when the first task
starts to run.
STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
portDISABLE_INTERRUPTS();
 
xSchedulerRunning = pdTRUE;
xTickCount = ( portTickType ) 0;
 
/* Setting up the timer tick is hardware specific and thus in the
portable interface. */
if( xPortStartScheduler() )
{
/* Should not reach here as if the scheduler is running the
function will not return. */
}
else
{
/* Should only reach here if a task calls xTaskEndScheduler(). */
}
}
}
/*-----------------------------------------------------------*/
 
void vTaskEndScheduler( void )
{
/* Stop the scheduler interrupts and call the portable scheduler end
routine so the original ISRs can be restored if necessary. The port
layer must ensure interrupts enable bit is left in the correct state. */
portDISABLE_INTERRUPTS();
xSchedulerRunning = pdFALSE;
vPortEndScheduler();
}
/*----------------------------------------------------------*/
 
void vTaskSuspendAll( void )
{
portENTER_CRITICAL();
++uxSchedulerSuspended;
portEXIT_CRITICAL();
}
/*----------------------------------------------------------*/
 
signed portBASE_TYPE xTaskResumeAll( void )
{
register tskTCB *pxTCB;
signed portBASE_TYPE xAlreadyYielded = pdFALSE;
 
/* It is possible that an ISR caused a task to be removed from an event
list while the scheduler was suspended. If this was the case then the
removed task will have been added to the xPendingReadyList. Once the
scheduler has been resumed it is safe to move all the pending ready
tasks from this list into their appropriate ready list. */
portENTER_CRITICAL();
{
--uxSchedulerSuspended;
 
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
{
if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
{
portBASE_TYPE xYieldRequired = pdFALSE;
/* Move any readied tasks from the pending list into the
appropriate ready list. */
while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
{
vListRemove( &( pxTCB->xEventListItem ) );
vListRemove( &( pxTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxTCB );
/* If we have moved a task that has a priority higher than
the current task then we should yield. */
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
xYieldRequired = pdTRUE;
}
}
 
/* If any ticks occurred while the scheduler was suspended then
they should be processed now. This ensures the tick count does not
slip, and that any delayed tasks are resumed at the correct time. */
if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
{
while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
{
vTaskIncrementTick();
--uxMissedTicks;
}
 
/* As we have processed some ticks it is appropriate to yield
to ensure the highest priority task that is ready to run is
the task actually running. */
xYieldRequired = pdTRUE;
}
if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
{
xAlreadyYielded = pdTRUE;
xMissedYield = pdFALSE;
taskYIELD();
}
}
}
}
portEXIT_CRITICAL();
 
return xAlreadyYielded;
}
 
 
 
 
 
 
/*-----------------------------------------------------------
* PUBLIC TASK UTILITIES documented in task.h
*----------------------------------------------------------*/
 
 
 
portTickType xTaskGetTickCount( void )
{
portTickType xTicks;
 
/* Critical section required if running on a 16 bit processor. */
taskENTER_CRITICAL();
{
xTicks = xTickCount;
}
taskEXIT_CRITICAL();
 
return xTicks;
}
/*-----------------------------------------------------------*/
 
unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
{
unsigned portBASE_TYPE uxNumberOfTasks;
 
taskENTER_CRITICAL();
uxNumberOfTasks = uxCurrentNumberOfTasks;
taskEXIT_CRITICAL();
 
return uxNumberOfTasks;
}
/*-----------------------------------------------------------*/
 
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_vTaskDelete == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
 
void vTaskList( signed portCHAR *pcWriteBuffer )
{
unsigned portBASE_TYPE uxQueue;
 
/* This is a VERY costly function that should be used for debug only.
It leaves interrupts disabled for a LONG time. */
 
vTaskSuspendAll();
{
/* Run through all the lists that could potentially contain a TCB and
report the task name, state and stack high water mark. */
 
pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
 
uxQueue = uxTopUsedPriority + 1;
 
do
{
uxQueue--;
 
if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
{
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
}
}while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
 
if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
{
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
}
 
if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
{
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
}
 
if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
{
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
}
 
if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
{
prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
}
}
xTaskResumeAll();
}
 
#endif
/*----------------------------------------------------------*/
 
#if ( configUSE_TRACE_FACILITY == 1 )
 
void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
{
portENTER_CRITICAL();
{
pcTraceBuffer = ( volatile signed portCHAR * volatile )pcBuffer;
pcTraceBufferStart = pcBuffer;
pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
xTracing = pdTRUE;
}
portEXIT_CRITICAL();
}
 
#endif
/*----------------------------------------------------------*/
 
#if ( configUSE_TRACE_FACILITY == 1 )
 
unsigned portLONG ulTaskEndTrace( void )
{
unsigned portLONG ulBufferLength;
 
portENTER_CRITICAL();
xTracing = pdFALSE;
portEXIT_CRITICAL();
 
ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
 
return ulBufferLength;
}
 
#endif
 
 
 
/*-----------------------------------------------------------
* SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
* documented in task.h
*----------------------------------------------------------*/
 
 
inline void vTaskIncrementTick( void )
{
/* Called by the portable layer each time a tick interrupt occurs.
Increments the tick then checks to see if the new tick value will cause any
tasks to be unblocked. */
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
{
++xTickCount;
if( xTickCount == ( portTickType ) 0 )
{
xList *pxTemp;
 
/* Tick count has overflowed so we need to swap the delay lists.
If there are any items in pxDelayedTaskList here then there is
an error! */
pxTemp = pxDelayedTaskList;
pxDelayedTaskList = pxOverflowDelayedTaskList;
pxOverflowDelayedTaskList = pxTemp;
xNumOfOverflows++;
}
 
/* See if this tick has made a timeout expire. */
prvCheckDelayedTasks();
}
else
{
++uxMissedTicks;
 
/* The tick hook gets called at regular intervals, even if the
scheduler is locked. */
#if ( configUSE_TICK_HOOK == 1 )
{
extern void vApplicationTickHook( void );
 
vApplicationTickHook();
}
#endif
}
 
#if ( configUSE_TICK_HOOK == 1 )
{
extern void vApplicationTickHook( void );
 
/* Guard against the tick hook being called when the missed tick
count is being unwound (when the scheduler is being unlocked. */
if( uxMissedTicks == 0 )
{
vApplicationTickHook();
}
}
#endif
}
/*-----------------------------------------------------------*/
 
#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
 
void vTaskCleanUpResources( void )
{
unsigned portSHORT usQueue;
volatile tskTCB *pxTCB;
 
usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
 
/* Remove any TCB's from the ready queues. */
do
{
usQueue--;
 
while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
{
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
 
prvDeleteTCB( ( tskTCB * ) pxTCB );
}
}while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
 
/* Remove any TCB's from the delayed queue. */
while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
{
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
 
prvDeleteTCB( ( tskTCB * ) pxTCB );
}
 
/* Remove any TCB's from the overflow delayed queue. */
while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
{
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
 
prvDeleteTCB( ( tskTCB * ) pxTCB );
}
 
while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
{
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
 
prvDeleteTCB( ( tskTCB * ) pxTCB );
}
 
while( !listLIST_IS_EMPTY( &xPendingReadyList ) )
{
listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xPendingReadyList );
vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
 
prvDeleteTCB( ( tskTCB * ) pxTCB );
}
}
 
#endif
/*-----------------------------------------------------------*/
 
void vTaskSwitchContext( void )
{
if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
{
/* The scheduler is currently suspended - do not allow a context
switch. */
xMissedYield = pdTRUE;
return;
}
 
/* Find the highest priority queue that contains ready tasks. */
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
{
--uxTopReadyPriority;
}
 
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
same priority get an equal share of the processor time. */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
vWriteTraceToBuffer();
}
/*-----------------------------------------------------------*/
 
void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait )
{
portTickType xTimeToWake;
 
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
SCHEDULER SUSPENDED. */
 
/* Place the event list item of the TCB in the appropriate event list.
This is placed in the list in priority order so the highest priority task
is the first to be woken by the event. */
vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
 
/* We must remove ourselves from the ready list before adding ourselves
to the blocked list as the same list item is used for both lists. We have
exclusive access to the ready lists as the scheduler is locked. */
vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
 
 
#if ( INCLUDE_vTaskSuspend == 1 )
{
if( xTicksToWait == portMAX_DELAY )
{
/* Add ourselves to the suspended task list instead of a delayed task
list to ensure we are not woken by a timing event. We will block
indefinitely. */
vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
else
{
/* Calculate the time at which the task should be woken if the event does
not occur. This may overflow but this doesn't matter. */
xTimeToWake = xTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
if( xTimeToWake < xTickCount )
{
/* Wake time has overflowed. Place this item in the overflow list. */
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the current block list. */
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
}
}
#else
{
/* Calculate the time at which the task should be woken if the event does
not occur. This may overflow but this doesn't matter. */
xTimeToWake = xTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
if( xTimeToWake < xTickCount )
{
/* Wake time has overflowed. Place this item in the overflow list. */
vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the current block list. */
vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
}
}
#endif
}
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList )
{
tskTCB *pxUnblockedTCB;
portBASE_TYPE xReturn;
 
/* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
SCHEDULER SUSPENDED. It can also be called from within an ISR. */
 
/* The event list is sorted in priority order, so we can remove the
first in the list, remove the TCB from the delayed list, and add
it to the ready list.
If an event is for a queue that is locked then this function will never
get called - the lock count on the queue will get modified instead. This
means we can always expect exclusive access to the event list here. */
pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
vListRemove( &( pxUnblockedTCB->xEventListItem ) );
 
if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
{
vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
prvAddTaskToReadyQueue( pxUnblockedTCB );
}
else
{
/* We cannot access the delayed or ready lists, so will hold this
task pending until the scheduler is resumed. */
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
}
 
if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
{
/* Return true if the task removed from the event list has
a higher priority than the calling task. This allows
the calling task to know if it should force a context
switch now. */
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
void vTaskSetTimeOutState( xTimeOutType *pxTimeOut )
{
pxTimeOut->xOverflowCount = xNumOfOverflows;
pxTimeOut->xTimeOnEntering = xTickCount;
}
/*-----------------------------------------------------------*/
 
portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType *pxTicksToWait )
{
portBASE_TYPE xReturn;
 
if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xTickCount >= pxTimeOut->xTimeOnEntering ) )
{
/* The tick count is greater than the time at which vTaskSetTimeout()
was called, but has also overflowed since vTaskSetTimeOut() was called.
It must have wrapped all the way around and gone past us again. This
passed since vTaskSetTimeout() was called. */
xReturn = pdTRUE;
}
else if( ( xTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
{
/* Not a genuine timeout. Adjust parameters for time remaining. */
*pxTicksToWait -= ( xTickCount - pxTimeOut->xTimeOnEntering );
vTaskSetTimeOutState( pxTimeOut );
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
 
return xReturn;
}
/*-----------------------------------------------------------*/
 
void vTaskMissedYield( void )
{
xMissedYield = pdTRUE;
}
 
/*
* -----------------------------------------------------------
* The Idle task.
* ----------------------------------------------------------
*
* The portTASK_FUNCTION() macro is used to allow port/compiler specific
* language extensions. The equivalent prototype for this function is:
*
* void prvIdleTask( void *pvParameters );
*
*/
static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
/* Stop warnings. */
( void ) pvParameters;
 
for( ;; )
{
/* See if any tasks have been deleted. */
prvCheckTasksWaitingTermination();
 
#if ( configUSE_PREEMPTION == 0 )
{
/* If we are not using preemption we keep forcing a task switch to
see if any other task has become available. If we are using
preemption we don't need to do this as any task becoming available
will automatically get the processor anyway. */
taskYIELD();
}
#endif
 
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
{
/* When using preemption tasks of equal priority will be
timesliced. If a task that is sharing the idle priority is ready
to run then the idle task should yield before the end of the
timeslice.
A critical region is not required here as we are just reading from
the list, and an occasional incorrect value will not matter. If
the ready list at the idle priority contains more than one task
then a task other than the idle task is ready to execute. */
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
{
taskYIELD();
}
}
#endif
 
#if ( configUSE_IDLE_HOOK == 1 )
{
extern void vApplicationIdleHook( void );
 
/* Call the user defined function from within the idle task. This
allows the application designer to add background functionality
without the overhead of a separate task.
NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
CALL A FUNCTION THAT MIGHT BLOCK. */
vApplicationIdleHook();
}
#endif
}
} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
 
 
 
 
 
 
 
/*-----------------------------------------------------------
* File private functions documented at the top of the file.
*----------------------------------------------------------*/
 
 
 
static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
{
pxTCB->usStackDepth = usStackDepth;
 
/* Store the function name in the TCB. */
strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
 
/* This is used as an array index so must ensure it's not too large. */
if( uxPriority >= configMAX_PRIORITIES )
{
uxPriority = configMAX_PRIORITIES - 1;
}
 
pxTCB->uxPriority = uxPriority;
 
vListInitialiseItem( &( pxTCB->xGenericListItem ) );
vListInitialiseItem( &( pxTCB->xEventListItem ) );
 
/* Set the pxTCB as a link back from the xListItem. This is so we can get
back to the containing TCB from a generic item in a list. */
listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
 
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
}
/*-----------------------------------------------------------*/
 
static void prvInitialiseTaskLists( void )
{
unsigned portBASE_TYPE uxPriority;
 
for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
}
 
vListInitialise( ( xList * ) &xDelayedTaskList1 );
vListInitialise( ( xList * ) &xDelayedTaskList2 );
vListInitialise( ( xList * ) &xPendingReadyList );
 
#if ( INCLUDE_vTaskDelete == 1 )
{
vListInitialise( ( xList * ) &xTasksWaitingTermination );
}
#endif
 
#if ( INCLUDE_vTaskSuspend == 1 )
{
vListInitialise( ( xList * ) &xSuspendedTaskList );
}
#endif
 
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
using list2. */
pxDelayedTaskList = &xDelayedTaskList1;
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
/*-----------------------------------------------------------*/
 
static void prvCheckTasksWaitingTermination( void )
{
#if ( INCLUDE_vTaskDelete == 1 )
{
portBASE_TYPE xListIsEmpty;
 
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
too often in the idle task. */
if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
{
vTaskSuspendAll();
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
xTaskResumeAll();
 
if( !xListIsEmpty )
{
tskTCB *pxTCB;
 
portENTER_CRITICAL();
{
pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
vListRemove( &( pxTCB->xGenericListItem ) );
--uxCurrentNumberOfTasks;
--uxTasksDeleted;
}
portEXIT_CRITICAL();
 
prvDeleteTCB( pxTCB );
}
}
}
#endif
}
/*-----------------------------------------------------------*/
 
static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth )
{
tskTCB *pxNewTCB;
 
/* Allocate space for the TCB. Where the memory comes from depends on
the implementation of the port malloc function. */
pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
 
if( pxNewTCB != NULL )
{
/* Allocate space for the stack used by the task being created.
The base of the stack memory stored in the TCB so the task can
be deleted later if required. */
pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) );
 
if( pxNewTCB->pxStack == NULL )
{
/* Could not allocate the stack. Delete the allocated TCB. */
vPortFree( pxNewTCB );
pxNewTCB = NULL;
}
else
{
/* Just to help debugging. */
memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
}
}
 
return pxNewTCB;
}
/*-----------------------------------------------------------*/
 
#if ( configUSE_TRACE_FACILITY == 1 )
 
static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
{
volatile tskTCB *pxNextTCB, *pxFirstTCB;
static portCHAR pcStatusString[ 50 ];
unsigned portSHORT usStackRemaining;
 
/* Write the details of all the TCB's in pxList into the buffer. */
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
do
{
listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
sprintf( pcStatusString, ( portCHAR * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
 
} while( pxNextTCB != pxFirstTCB );
}
 
#endif
/*-----------------------------------------------------------*/
 
#if ( configUSE_TRACE_FACILITY == 1 )
unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte )
{
register unsigned portSHORT usCount = 0;
 
while( *pucStackByte == tskSTACK_FILL_BYTE )
{
pucStackByte -= portSTACK_GROWTH;
usCount++;
}
 
usCount /= sizeof( portSTACK_TYPE );
 
return usCount;
}
#endif
/*-----------------------------------------------------------*/
 
 
 
#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
 
static void prvDeleteTCB( tskTCB *pxTCB )
{
/* Free up the memory allocated by the scheduler for the task. It is up to
the task to free any memory allocated at the application level. */
vPortFree( pxTCB->pxStack );
vPortFree( pxTCB );
}
 
#endif
 
 
/*-----------------------------------------------------------*/
 
#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
 
xTaskHandle xTaskGetCurrentTaskHandle( void )
{
xTaskHandle xReturn;
 
portENTER_CRITICAL();
{
xReturn = ( xTaskHandle ) pxCurrentTCB;
}
portEXIT_CRITICAL();
 
return xReturn;
}
 
#endif
 
 
 
 
 
/trunk/sw/freertos/croutine.c
0,0 → 1,342
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
 
/* Lists for ready and blocked co-routines. --------------------*/
static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
static xList xDelayedCoRoutineList1; /*< Delayed co-routines. */
static xList xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
static xList * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
static xList * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
static xList xPendingReadyList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
 
/* Other file private variables. --------------------------------*/
corCRCB * pxCurrentCoRoutine = NULL;
static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
static portTickType xCoRoutineTickCount = 0;
 
/* The initial state of the co-routine when it is created. */
#define corINITIAL_STATE ( 0 )
 
/*
* Place the co-routine represented by pxCRCB into the appropriate ready queue
* for the priority. It is inserted at the end of the list.
*
* This macro accesses the co-routine ready lists and therefore must not be
* used from within an ISR.
*/
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
{ \
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
{ \
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
} \
vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
}
 
/*
* Utility to ready all the lists used by the scheduler. This is called
* automatically upon the creation of the first co-routine.
*/
static void prvInitialiseCoRoutineLists( void );
 
/*
* Co-routines that are readied by an interrupt cannot be placed directly into
* the ready lists (there is no mutual exclusion). Instead they are placed in
* in the pending ready list in order that they can later be moved to the ready
* list by the co-routine scheduler.
*/
static inline void prvCheckPendingReadyList( void );
 
/*
* Macro that looks at the list of co-routines that are currently delayed to
* see if any require waking.
*
* Co-routines are stored in the queue in the order of their wake time -
* meaning once one co-routine has been found whose timer has not expired
* we need not look any further down the list.
*/
static inline void prvCheckDelayedList( void );
 
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
{
signed portBASE_TYPE xReturn;
corCRCB *pxCoRoutine;
 
/* Allocate the memory that will store the co-routine control block. */
pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
if( pxCoRoutine )
{
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
be created and the co-routine data structures need initialising. */
if( pxCurrentCoRoutine == NULL )
{
pxCurrentCoRoutine = pxCoRoutine;
prvInitialiseCoRoutineLists();
}
 
/* Check the priority is within limits. */
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
{
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
}
 
/* Fill out the co-routine control block from the function parameters. */
pxCoRoutine->uxState = corINITIAL_STATE;
pxCoRoutine->uxPriority = uxPriority;
pxCoRoutine->uxIndex = uxIndex;
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
 
/* Initialise all the other co-routine control block parameters. */
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
 
/* Set the co-routine control block as a link back from the xListItem.
This is so we can get back to the containing CRCB from a generic item
in a list. */
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
/* Now the co-routine has been initialised it can be added to the ready
list at the correct priority. */
prvAddCoRoutineToReadyQueue( pxCoRoutine );
 
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
/*-----------------------------------------------------------*/
 
void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
{
portTickType xTimeToWake;
 
/* Calculate the time to wake - this may overflow but this is
not a problem. */
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
 
/* We must remove ourselves from the ready list before adding
ourselves to the blocked list as the same list item is used for
both lists. */
vListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
 
/* The list item will be inserted in wake time order. */
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
 
if( xTimeToWake < xCoRoutineTickCount )
{
/* Wake time has overflowed. Place this item in the
overflow list. */
vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
else
{
/* The wake time has not overflowed, so we can use the
current block list. */
vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
}
 
if( pxEventList )
{
/* Also add the co-routine to an event list. If this is done then the
function must be called with interrupts disabled. */
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
}
}
/*-----------------------------------------------------------*/
 
static inline void prvCheckPendingReadyList( void )
{
/* Are there any co-routines waiting to get moved to the ready list? These
are co-routines that have been readied by an ISR. The ISR cannot access
the ready lists itself. */
while( !listLIST_IS_EMPTY( &xPendingReadyList ) )
{
corCRCB *pxUnblockedCRCB;
 
/* The pending ready list can be accessed by an ISR. */
portDISABLE_INTERRUPTS();
{
pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyList) );
vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
}
portENABLE_INTERRUPTS();
 
vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
}
}
/*-----------------------------------------------------------*/
 
static inline void prvCheckDelayedList( void )
{
static portTickType xLastTickCount, xPassedTicks;
corCRCB *pxCRCB;
 
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
while( xPassedTicks )
{
xCoRoutineTickCount++;
xPassedTicks--;
 
/* If the tick count has overflowed we need to swap the ready lists. */
if( xCoRoutineTickCount == 0 )
{
xList * pxTemp;
 
/* Tick count has overflowed so we need to swap the delay lists. If there are
any items in pxDelayedCoRoutineList here then there is an error! */
pxTemp = pxDelayedCoRoutineList;
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
pxOverflowDelayedCoRoutineList = pxTemp;
}
 
/* See if this tick has made a timeout expire. */
while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL )
{
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
{
/* Timeout not yet expired. */
break;
}
 
portDISABLE_INTERRUPTS();
{
/* The event could have occurred just before this critical
section. If this is the case then the generic list item will
have been moved to the pending ready list and the following
line is still valid. Also the pvContainer parameter will have
been set to NULL so the following lines are also valid. */
vListRemove( &( pxCRCB->xGenericListItem ) );
 
/* Is the co-routine waiting on an event also? */
if( pxCRCB->xEventListItem.pvContainer )
{
vListRemove( &( pxCRCB->xEventListItem ) );
}
}
portENABLE_INTERRUPTS();
 
prvAddCoRoutineToReadyQueue( pxCRCB );
}
}
 
xLastTickCount = xCoRoutineTickCount;
}
/*-----------------------------------------------------------*/
 
void vCoRoutineSchedule( void )
{
/* See if any co-routines readied by events need moving to the ready lists. */
prvCheckPendingReadyList();
 
/* See if any delayed co-routines have timed out. */
prvCheckDelayedList();
 
/* Find the highest priority queue that contains ready co-routines. */
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
{
if( uxTopCoRoutineReadyPriority == 0 )
{
/* No more co-routines to check. */
return;
}
--uxTopCoRoutineReadyPriority;
}
 
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
of the same priority get an equal share of the processor time. */
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
 
/* Call the co-routine. */
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
 
return;
}
/*-----------------------------------------------------------*/
 
static void prvInitialiseCoRoutineLists( void )
{
unsigned portBASE_TYPE uxPriority;
 
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
{
vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
}
 
vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
vListInitialise( ( xList * ) &xPendingReadyList );
 
/* Start with pxDelayedCoRoutineList using list1 and the
pxOverflowDelayedCoRoutineList using list2. */
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
}
/*-----------------------------------------------------------*/
 
signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
{
corCRCB *pxUnblockedCRCB;
signed portBASE_TYPE xReturn;
 
/* This function is called from within an interrupt. It can only access
event lists and the pending ready list. */
pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedCRCB->xEventListItem ) );
 
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
 
return xReturn;
}
 
/trunk/sw/freertos/queue.h
0,0 → 1,471
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
 
#ifndef QUEUE_H
#define QUEUE_H
 
typedef void * xQueueHandle;
 
/**
* queue. h
* <pre>
xQueueHandle xQueueCreate(
unsigned portBASE_TYPE uxQueueLength,
unsigned portBASE_TYPE uxItemSize
);
* </pre>
*
* Creates a new queue instance. This allocates the storage required by the
* new queue and returns a handle for the queue.
*
* @param uxQueueLength The maximum number of items that the queue can contain.
*
* @param uxItemSize The number of bytes each item in the queue will require.
* Items are queued by copy, not by reference, so this is the number of bytes
* that will be copied for each posted item. Each item on the queue must be
* the same size.
*
* @return If the queue is successfully create then a handle to the newly
* created queue is returned. If the queue cannot be created then 0 is
* returned.
*
* Example usage:
<pre>
struct AMessage
{
portCHAR ucMessageID;
portCHAR ucData[ 20 ];
};
 
void vATask( void *pvParameters )
{
xQueueHandle xQueue1, xQueue2;
 
// Create a queue capable of containing 10 unsigned long values.
xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
if( xQueue1 == 0 )
{
// Queue was not created and must not be used.
}
 
// Create a queue capable of containing 10 pointers to AMessage structures.
// These should be passed by pointer as they contain a lot of data.
xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
if( xQueue2 == 0 )
{
// Queue was not created and must not be used.
}
 
// ... Rest of task code.
}
</pre>
* \defgroup xQueueCreate xQueueCreate
* \ingroup QueueManagement
*/
xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
 
/**
* queue. h
* <pre>
portBASE_TYPE xQueueSend(
xQueueHandle xQueue,
const void * pvItemToQueue,
portTickType xTicksToWait
);
* </pre>
*
* Post an item on a queue. The item is queued by copy, not by reference.
* This function must not be called from an interrupt service routine.
* See xQueueSendFromISR () for an alternative which may be used in an ISR.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param xTicksToWait The maximum amount of time the task should block
* waiting for space to become available on the queue, should it already
* be full. The call will return immediately if this is set to 0. The
* time is defined in tick periods so the constant portTICK_RATE_MS
* should be used to convert to real time if this is required.
*
* @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
*
* Example usage:
<pre>
struct AMessage
{
portCHAR ucMessageID;
portCHAR ucData[ 20 ];
} xMessage;
 
unsigned portLONG ulVar = 10UL;
 
void vATask( void *pvParameters )
{
xQueueHandle xQueue1, xQueue2;
struct AMessage *pxMessage;
 
// Create a queue capable of containing 10 unsigned long values.
xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
 
// Create a queue capable of containing 10 pointers to AMessage structures.
// These should be passed by pointer as they contain a lot of data.
xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
 
// ...
 
if( xQueue1 != 0 )
{
// Send an unsigned long. Wait for 10 ticks for space to become
// available if necessary.
if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
{
// Failed to post the message, even after 10 ticks.
}
}
 
if( xQueue2 != 0 )
{
// Send a pointer to a struct AMessage object. Don't block if the
// queue is already full.
pxMessage = & xMessage;
xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
}
 
// ... Rest of task code.
}
</pre>
* \defgroup xQueueSend xQueueSend
* \ingroup QueueManagement
*/
signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
 
/**
* queue. h
* <pre>
portBASE_TYPE xQueueReceive(
xQueueHandle xQueue,
void *pvBuffer,
portTickType xTicksToWait
);</pre>
*
* Receive an item from a queue. The item is received by copy so a buffer of
* adequate size must be provided. The number of bytes copied into the buffer
* was defined when the queue was created.
*
* This function must not be used in an interrupt service routine. See
* xQueueReceiveFromISR for an alternative that can.
*
* @param pxQueue The handle to the queue from which the item is to be
* received.
*
* @param pvBuffer Pointer to the buffer into which the received item will
* be copied.
*
* @param xTicksToWait The maximum amount of time the task should block
* waiting for an item to receive should the queue be empty at the time
* of the call. The time is defined in tick periods so the constant
* portTICK_RATE_MS should be used to convert to real time if this is required.
*
* @return pdTRUE if an item was successfully received from the queue,
* otherwise pdFALSE.
*
* Example usage:
<pre>
struct AMessage
{
portCHAR ucMessageID;
portCHAR ucData[ 20 ];
} xMessage;
 
xQueueHandle xQueue;
// Task to create a queue and post a value.
void vATask( void *pvParameters )
{
struct AMessage *pxMessage;
 
// Create a queue capable of containing 10 pointers to AMessage structures.
// These should be passed by pointer as they contain a lot of data.
xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
if( xQueue == 0 )
{
// Failed to create the queue.
}
 
// ...
 
// Send a pointer to a struct AMessage object. Don't block if the
// queue is already full.
pxMessage = & xMessage;
xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
 
// ... Rest of task code.
}
 
// Task to receive from the queue.
void vADifferentTask( void *pvParameters )
{
struct AMessage *pxRxedMessage;
 
if( xQueue != 0 )
{
// Receive a message on the created queue. Block for 10 ticks if a
// message is not immediately available.
if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
{
// pcRxedMessage now points to the struct AMessage variable posted
// by vATask.
}
}
 
// ... Rest of task code.
}
</pre>
* \defgroup xQueueReceive xQueueReceive
* \ingroup QueueManagement
*/
signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait );
 
/**
* queue. h
* <pre>unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );</pre>
*
* Return the number of messages stored in a queue.
*
* @param xQueue A handle to the queue being queried.
*
* @return The number of messages available in the queue.
*
* \page uxQueueMessagesWaiting uxQueueMessagesWaiting
* \ingroup QueueManagement
*/
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );
 
/**
* queue. h
* <pre>void vQueueDelete( xQueueHandle xQueue );</pre>
*
* Delete a queue - freeing all the memory allocated for storing of items
* placed on the queue.
*
* @param xQueue A handle to the queue to be deleted.
*
* \page vQueueDelete vQueueDelete
* \ingroup QueueManagement
*/
void vQueueDelete( xQueueHandle xQueue );
 
/**
* queue. h
* <pre>
portBASE_TYPE xQueueSendFromISR(
xQueueHandle pxQueue,
const void *pvItemToQueue,
portBASE_TYPE xTaskPreviouslyWoken
);
</pre>
*
* Post an item on a queue. It is safe to use this function from within an
* interrupt service routine.
*
* Items are queued by copy not reference so it is preferable to only
* queue small items, especially when called from an ISR. In most cases
* it would be preferable to store a pointer to the item being queued.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param cTaskPreviouslyWoken This is included so an ISR can post onto
* the same queue multiple times from a single interrupt. The first call
* should always pass in pdFALSE. Subsequent calls should pass in
* the value returned from the previous call. See the file serial .c in the
* PC port for a good example of this mechanism.
*
* @return pdTRUE if a task was woken by posting onto the queue. This is
* used by the ISR to determine if a context switch may be required following
* the ISR.
*
* Example usage for buffered IO (where the ISR can obtain more than one value
* per call):
<pre>
void vBufferISR( void )
{
portCHAR cIn;
portBASE_TYPE xTaskWokenByPost;
 
// We have not woken a task at the start of the ISR.
cTaskWokenByPost = pdFALSE;
 
// Loop until the buffer is empty.
do
{
// Obtain a byte from the buffer.
cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
 
// Post the byte. The first time round the loop cTaskWokenByPost
// will be pdFALSE. If the queue send causes a task to wake we do
// not want the task to run until we have finished the ISR, so
// xQueueSendFromISR does not cause a context switch. Also we
// don't want subsequent posts to wake any other tasks, so we store
// the return value back into cTaskWokenByPost so xQueueSendFromISR
// knows not to wake any task the next iteration of the loop.
xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost );
 
} while( portINPUT_BYTE( BUFFER_COUNT ) );
 
// Now the buffer is empty we can switch context if necessary.
if( cTaskWokenByPost )
{
taskYIELD ();
}
}
</pre>
*
* \defgroup xQueueSendFromISR xQueueSendFromISR
* \ingroup QueueManagement
*/
signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
 
/**
* queue. h
* <pre>
portBASE_TYPE xQueueReceiveFromISR(
xQueueHandle pxQueue,
void *pvBuffer,
portBASE_TYPE *pxTaskWoken
);
* </pre>
*
* Receive an item from a queue. It is safe to use this function from within an
* interrupt service routine.
*
* @param pxQueue The handle to the queue from which the item is to be
* received.
*
* @param pvBuffer Pointer to the buffer into which the received item will
* be copied.
*
* @param pxTaskWoken A task may be blocked waiting for space to become
* available on the queue. If xQueueReceiveFromISR causes such a task to
* unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will
* remain unchanged.
*
* @return pdTRUE if an item was successfully received from the queue,
* otherwise pdFALSE.
*
* Example usage:
<pre>
xQueueHandle xQueue;
// Function to create a queue and post some values.
void vAFunction( void *pvParameters )
{
portCHAR cValueToPost;
const portTickType xBlockTime = ( portTickType )0xff;
 
// Create a queue capable of containing 10 characters.
xQueue = xQueueCreate( 10, sizeof( portCHAR ) );
if( xQueue == 0 )
{
// Failed to create the queue.
}
 
// ...
 
// Post some characters that will be used within an ISR. If the queue
// is full then this task will block for xBlockTime ticks.
cValueToPost = 'a';
xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
cValueToPost = 'b';
xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
 
// ... keep posting characters ... this task may block when the queue
// becomes full.
 
cValueToPost = 'c';
xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
}
 
// ISR that outputs all the characters received on the queue.
void vISR_Routine( void )
{
portBASE_TYPE xTaskWokenByReceive = pdFALSE;
portCHAR cRxedChar;
 
while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
{
// A character was received. Output the character now.
vOutputCharacter( cRxedChar );
 
// If removing the character from the queue woke the task that was
// posting onto the queue cTaskWokenByReceive will have been set to
// pdTRUE. No matter how many times this loop iterates only one
// task will be woken.
}
 
if( cTaskWokenByPost != ( portCHAR ) pdFALSE;
{
taskYIELD ();
}
}
</pre>
* \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
* \ingroup QueueManagement
*/
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
 
 
/*
* The functions defined above are for passing data to and from tasks. The
* functions below are the equivalents for passing data to and from
* co-rtoutines.
*
* These functions are called from the co-routine macro implementation and
* should not be called directly from application code. Instead use the macro
* wrappers defined within croutine.h.
*/
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
 
#endif
 
/trunk/sw/freertos/Makefile
0,0 → 1,28
PRJ = freertos
LIBS = portasm.s
LIB = croutine.c heap_2.c list.c port.c queue.c tasks.c
OBJS = $(LIB:.c=.o)
OBJSS= $(LIBS:.s=.o)
 
$(PRJ): $(OBJS) $(OBJSS)
--rm lib$(PRJ).a
mb-ar q lib$(PRJ).a $(OBJS) $(OBJSS)
 
$(OBJS): $(LIB)
mb-gcc -I . -I ../lib -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
 
$(OBJSS): $(LIBS)
mb-as -ahlms=$(@:.o=.lst) -o $@ $(@:.o=.s)
 
clean:
-rm *.o
-rm *.out
-rm *.bin
-rm *.v
-rm *.map
-rm *.lst
-rm *.bak
-rm *.srec
-rm *.prom
-rm *.rom
-rm *.a
/trunk/sw/freertos/croutine.h
0,0 → 1,713
/*
FreeRTOS.org V4.2.0 - Copyright (C) 2003-2007 Richard Barry.
 
This file is part of the FreeRTOS.org distribution.
 
FreeRTOS.org is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
FreeRTOS.org is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with FreeRTOS.org; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes FreeRTOS.org, without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details of how and when the exception
can be applied.
 
***************************************************************************
See http://www.FreeRTOS.org for documentation, latest information, license
and contact details. Please ensure to read the configuration and relevant
port sections of the online documentation.
***************************************************************************
*/
#ifndef CO_ROUTINE_H
#define CO_ROUTINE_H
 
#include "list.h"
 
/* Used to hide the implementation of the co-routine control block. The
control block structure however has to be included in the header due to
the macro implementation of the co-routine functionality. */
typedef void * xCoRoutineHandle;
 
/* Defines the prototype to which co-routine functions must conform. */
typedef void (*crCOROUTINE_CODE)( xCoRoutineHandle, unsigned portBASE_TYPE );
 
typedef struct corCoRoutineControlBlock
{
crCOROUTINE_CODE pxCoRoutineFunction;
xListItem xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
xListItem xEventListItem; /*< List item used to place the CRCB in event lists. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
unsigned portBASE_TYPE uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
unsigned portSHORT uxState; /*< Used internally by the co-routine implementation. */
} corCRCB; /* Co-routine control block. Note must be identical in size down to uxPriority with tskTCB. */
 
/**
* croutine. h
*<pre>
portBASE_TYPE xCoRoutineCreate(
crCOROUTINE_CODE pxCoRoutineCode,
unsigned portBASE_TYPE uxPriority,
unsigned portBASE_TYPE uxIndex
);</pre>
*
* Create a new co-routine and add it to the list of co-routines that are
* ready to run.
*
* @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
* functions require special syntax - see the co-routine section of the WEB
* documentation for more information.
*
* @param uxPriority The priority with respect to other co-routines at which
* the co-routine will run.
*
* @param uxIndex Used to distinguish between different co-routines that
* execute the same function. See the example below and the co-routine section
* of the WEB documentation for further information.
*
* @return pdPASS if the co-routine was successfully created and added to a ready
* list, otherwise an error code defined with ProjDefs.h.
*
* Example usage:
<pre>
// Co-routine to be created.
void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
// This may not be necessary for const variables.
static const char cLedToFlash[ 2 ] = { 5, 6 };
static const portTickType xTimeToDelay[ 2 ] = { 200, 400 };
 
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
 
for( ;; )
{
// This co-routine just delays for a fixed period, then toggles
// an LED. Two co-routines are created using this function, so
// the uxIndex parameter is used to tell the co-routine which
// LED to flash and how long to delay. This assumes xQueue has
// already been created.
vParTestToggleLED( cLedToFlash[ uxIndex ] );
crDELAY( xHandle, uxFlashRates[ uxIndex ] );
}
 
// Must end every co-routine with a call to crEND();
crEND();
}
 
// Function that creates two co-routines.
void vOtherFunction( void )
{
unsigned char ucParameterToPass;
xTaskHandle xHandle;
// Create two co-routines at priority 0. The first is given index 0
// so (from the code above) toggles LED 5 every 200 ticks. The second
// is given index 1 so toggles LED 6 every 400 ticks.
for( uxIndex = 0; uxIndex < 2; uxIndex++ )
{
xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
}
}
</pre>
* \defgroup xCoRoutineCreate xCoRoutineCreate
* \ingroup Tasks
*/
signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex );
 
 
/**
* croutine. h
*<pre>
void vCoRoutineSchedule( void );</pre>
*
* Run a co-routine.
*
* vCoRoutineSchedule() executes the highest priority co-routine that is able
* to run. The co-routine will execute until it either blocks, yields or is
* preempted by a task. Co-routines execute cooperatively so one
* co-routine cannot be preempted by another, but can be preempted by a task.
*
* If an application comprises of both tasks and co-routines then
* vCoRoutineSchedule should be called from the idle task (in an idle task
* hook).
*
* Example usage:
<pre>
// This idle task hook will schedule a co-routine each time it is called.
// The rest of the idle task will execute between co-routine calls.
void vApplicationIdleHook( void )
{
vCoRoutineSchedule();
}
 
// Alternatively, if you do not require any other part of the idle task to
// execute, the idle task hook can call vCoRoutineScheduler() within an
// infinite loop.
void vApplicationIdleHook( void )
{
for( ;; )
{
vCoRoutineSchedule();
}
}
</pre>
* \defgroup vCoRoutineSchedule vCoRoutineSchedule
* \ingroup Tasks
*/
void vCoRoutineSchedule( void );
 
/**
* croutine. h
* <pre>
crSTART( xCoRoutineHandle xHandle );</pre>
*
* This macro MUST always be called at the start of a co-routine function.
*
* Example usage:
<pre>
// Co-routine to be created.
void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static portLONG ulAVariable;
 
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
 
for( ;; )
{
// Co-routine functionality goes here.
}
 
// Must end every co-routine with a call to crEND();
crEND();
}</pre>
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
#define crSTART( pxCRCB ) switch( ( ( corCRCB * )pxCRCB )->uxState ) { case 0:
 
/**
* croutine. h
* <pre>
crEND();</pre>
*
* This macro MUST always be called at the end of a co-routine function.
*
* Example usage:
<pre>
// Co-routine to be created.
void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static portLONG ulAVariable;
 
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
 
for( ;; )
{
// Co-routine functionality goes here.
}
 
// Must end every co-routine with a call to crEND();
crEND();
}</pre>
* \defgroup crSTART crSTART
* \ingroup Tasks
*/
#define crEND() }
 
/*
* These macros are intended for internal use by the co-routine implementation
* only. The macros should not be used directly by application writers.
*/
#define crSET_STATE0( xHandle ) ( ( corCRCB * )xHandle)->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
#define crSET_STATE1( xHandle ) ( ( corCRCB * )xHandle)->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
 
/**
* croutine. h
*<pre>
crDELAY( xCoRoutineHandle xHandle, portTickType xTicksToDelay );</pre>
*
* Delay a co-routine for a fixed period of time.
*
* crDELAY can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* @param xHandle The handle of the co-routine to delay. This is the xHandle
* parameter of the co-routine function.
*
* @param xTickToDelay The number of ticks that the co-routine should delay
* for. The actual amount of time this equates to is defined by
* configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_RATE_MS
* can be used to convert ticks to milliseconds.
*
* Example usage:
<pre>
// Co-routine to be created.
void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
// This may not be necessary for const variables.
// We are to delay for 200ms.
static const xTickType xDelayTime = 200 / portTICK_RATE_MS;
 
// Must start every co-routine with a call to crSTART();
crSTART( xHandle );
 
for( ;; )
{
// Delay for 200ms.
crDELAY( xHandle, xDelayTime );
 
// Do something here.
}
 
// Must end every co-routine with a call to crEND();
crEND();
}</pre>
* \defgroup crDELAY crDELAY
* \ingroup Tasks
*/
#define crDELAY( xHandle, xTicksToDelay ) \
if( xTicksToDelay > 0 ) \
{ \
vCoRoutineAddToDelayedList( xTicksToDelay, NULL ); \
} \
crSET_STATE0( xHandle );
 
/**
* <pre>
crQUEUE_SEND(
xCoRoutineHandle xHandle,
xQueueHandle pxQueue,
void *pvItemToQueue,
portTickType xTicksToWait,
portBASE_TYPE *pxResult
)</pre>
*
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
*
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
* xQueueSend() and xQueueReceive() can only be used from tasks.
*
* crQUEUE_SEND can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xHandle The handle of the calling co-routine. This is the xHandle
* parameter of the co-routine function.
*
* @param pxQueue The handle of the queue on which the data will be posted.
* The handle is obtained as the return value when the queue is created using
* the xQueueCreate() API function.
*
* @param pvItemToQueue A pointer to the data being posted onto the queue.
* The number of bytes of each queued item is specified when the queue is
* created. This number of bytes is copied from pvItemToQueue into the queue
* itself.
*
* @param xTickToDelay The number of ticks that the co-routine should block
* to wait for space to become available on the queue, should space not be
* available immediately. The actual amount of time this equates to is defined
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
* portTICK_RATE_MS can be used to convert ticks to milliseconds (see example
* below).
*
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
* data was successfully posted onto the queue, otherwise it will be set to an
* error defined within ProjDefs.h.
*
* Example usage:
<pre>
// Co-routine function that blocks for a fixed period then posts a number onto
// a queue.
static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static portBASE_TYPE xNumberToPost = 0;
static portBASE_TYPE xResult;
 
// Co-routines must begin with a call to crSTART().
crSTART( xHandle );
 
for( ;; )
{
// This assumes the queue has already been created.
crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
 
if( xResult != pdPASS )
{
// The message was not posted!
}
 
// Increment the number to be posted onto the queue.
xNumberToPost++;
 
// Delay for 100 ticks.
crDELAY( xHandle, 100 );
}
 
// Co-routines must end with a call to crEND().
crEND();
}</pre>
* \defgroup crQUEUE_SEND crQUEUE_SEND
* \ingroup Tasks
*/
#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
{ \
*pxResult = xQueueCRSend( pxQueue, pvItemToQueue, xTicksToWait ); \
if( *pxResult == errQUEUE_BLOCKED ) \
{ \
crSET_STATE0( xHandle ); \
*pxResult = xQueueCRSend( pxQueue, pvItemToQueue, 0 ); \
} \
if( *pxResult == errQUEUE_YIELD ) \
{ \
crSET_STATE1( xHandle ); \
*pxResult = pdPASS; \
} \
}
 
/**
* croutine. h
* <pre>
crQUEUE_RECEIVE(
xCoRoutineHandle xHandle,
xQueueHandle pxQueue,
void *pvBuffer,
portTickType xTicksToWait,
portBASE_TYPE *pxResult
)</pre>
*
* The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
* equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
*
* crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
* xQueueSend() and xQueueReceive() can only be used from tasks.
*
* crQUEUE_RECEIVE can only be called from the co-routine function itself - not
* from within a function called by the co-routine function. This is because
* co-routines do not maintain their own stack.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xHandle The handle of the calling co-routine. This is the xHandle
* parameter of the co-routine function.
*
* @param pxQueue The handle of the queue from which the data will be received.
* The handle is obtained as the return value when the queue is created using
* the xQueueCreate() API function.
*
* @param pvBuffer The buffer into which the received item is to be copied.
* The number of bytes of each queued item is specified when the queue is
* created. This number of bytes is copied into pvBuffer.
*
* @param xTickToDelay The number of ticks that the co-routine should block
* to wait for data to become available from the queue, should data not be
* available immediately. The actual amount of time this equates to is defined
* by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
* portTICK_RATE_MS can be used to convert ticks to milliseconds (see the
* crQUEUE_SEND example).
*
* @param pxResult The variable pointed to by pxResult will be set to pdPASS if
* data was successfully retrieved from the queue, otherwise it will be set to
* an error code as defined within ProjDefs.h.
*
* Example usage:
<pre>
// A co-routine receives the number of an LED to flash from a queue. It
// blocks on the queue until the number is received.
static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// Variables in co-routines must be declared static if they must maintain value across a blocking call.
static portBASE_TYPE xResult;
static unsigned portBASE_TYPE uxLEDToFlash;
 
// All co-routines must start with a call to crSTART().
crSTART( xHandle );
 
for( ;; )
{
// Wait for data to become available on the queue.
crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
 
if( xResult == pdPASS )
{
// We received the LED to flash - flash it!
vParTestToggleLED( uxLEDToFlash );
}
}
 
crEND();
}</pre>
* \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
* \ingroup Tasks
*/
#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
{ \
*pxResult = xQueueCRReceive( pxQueue, pvBuffer, xTicksToWait ); \
if( *pxResult == errQUEUE_BLOCKED ) \
{ \
crSET_STATE0( xHandle ); \
*pxResult = xQueueCRReceive( pxQueue, pvBuffer, 0 ); \
} \
if( *pxResult == errQUEUE_YIELD ) \
{ \
crSET_STATE1( xHandle ); \
*pxResult = pdPASS; \
} \
}
 
/**
* croutine. h
* <pre>
crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue,
void *pvItemToQueue,
portBASE_TYPE xCoRoutinePreviouslyWoken
)</pre>
*
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
* functions used by tasks.
*
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
* xQueueReceiveFromISR() can only be used to pass data between a task and and
* ISR.
*
* crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
* that is being used from within a co-routine.
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvItemToQueue A pointer to the item that is to be placed on the
* queue. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from pvItemToQueue
* into the queue storage area.
*
* @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
* the same queue multiple times from a single interrupt. The first call
* should always pass in pdFALSE. Subsequent calls should pass in
* the value returned from the previous call.
*
* @return pdTRUE if a co-routine was woken by posting onto the queue. This is
* used by the ISR to determine if a context switch may be required following
* the ISR.
*
* Example usage:
<pre>
// A co-routine that blocks on a queue waiting for characters to be received.
static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
portCHAR cRxedChar;
portBASE_TYPE xResult;
 
// All co-routines must start with a call to crSTART().
crSTART( xHandle );
 
for( ;; )
{
// Wait for data to become available on the queue. This assumes the
// queue xCommsRxQueue has already been created!
crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
 
// Was a character received?
if( xResult == pdPASS )
{
// Process the character here.
}
}
 
// All co-routines must end with a call to crEND().
crEND();
}
 
// An ISR that uses a queue to send characters received on a serial port to
// a co-routine.
void vUART_ISR( void )
{
portCHAR cRxedChar;
portBASE_TYPE xCRWokenByPost = pdFALSE;
 
// We loop around reading characters until there are none left in the UART.
while( UART_RX_REG_NOT_EMPTY() )
{
// Obtain the character from the UART.
cRxedChar = UART_RX_REG;
 
// Post the character onto a queue. xCRWokenByPost will be pdFALSE
// the first time around the loop. If the post causes a co-routine
// to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
// In this manner we can ensure that if more than one co-routine is
// blocked on the queue only one is woken by this ISR no matter how
// many characters are posted to the queue.
xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
}
}</pre>
* \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
* \ingroup Tasks
*/
#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken )
 
 
/**
* croutine. h
* <pre>
crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue,
void *pvBuffer,
portBASE_TYPE * pxCoRoutineWoken
)</pre>
*
* The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
* co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
* functions used by tasks.
*
* crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
* pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
* xQueueReceiveFromISR() can only be used to pass data between a task and and
* ISR.
*
* crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
* from a queue that is being used from within a co-routine (a co-routine
* posted to the queue).
*
* See the co-routine section of the WEB documentation for information on
* passing data between tasks and co-routines and between ISR's and
* co-routines.
*
* @param xQueue The handle to the queue on which the item is to be posted.
*
* @param pvBuffer A pointer to a buffer into which the received item will be
* placed. The size of the items the queue will hold was defined when the
* queue was created, so this many bytes will be copied from the queue into
* pvBuffer.
*
* @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
* available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
* co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
* *pxCoRoutineWoken will remain unchanged.
*
* @return pdTRUE an item was successfully received from the queue, otherwise
* pdFALSE.
*
* Example usage:
<pre>
// A co-routine that posts a character to a queue then blocks for a fixed
// period. The character is incremented each time.
static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
{
// cChar holds its value while this co-routine is blocked and must therefore
// be declared static.
static portCHAR cCharToTx = 'a';
portBASE_TYPE xResult;
 
// All co-routines must start with a call to crSTART().
crSTART( xHandle );
 
for( ;; )
{
// Send the next character to the queue.
crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
 
if( xResult == pdPASS )
{
// The character was successfully posted to the queue.
}
else
{
// Could not post the character to the queue.
}
 
// Enable the UART Tx interrupt to cause an interrupt in this
// hypothetical UART. The interrupt will obtain the character
// from the queue and send it.
ENABLE_RX_INTERRUPT();
 
// Increment to the next character then block for a fixed period.
// cCharToTx will maintain its value across the delay as it is
// declared static.
cCharToTx++;
if( cCharToTx > 'x' )
{
cCharToTx = 'a';
}
crDELAY( 100 );
}
 
// All co-routines must end with a call to crEND().
crEND();
}
 
// An ISR that uses a queue to receive characters to send on a UART.
void vUART_ISR( void )
{
portCHAR cCharToTx;
portBASE_TYPE xCRWokenByPost = pdFALSE;
 
while( UART_TX_REG_EMPTY() )
{
// Are there any characters in the queue waiting to be sent?
// xCRWokenByPost will automatically be set to pdTRUE if a co-routine
// is woken by the post - ensuring that only a single co-routine is
// woken no matter how many times we go around this loop.
if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
{
SEND_CHARACTER( cCharToTx );
}
}
}</pre>
* \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
* \ingroup Tasks
*/
#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( pxQueue, pvBuffer, pxCoRoutineWoken )
 
/*
* This function is intended for internal use by the co-routine macros only.
* The macro nature of the co-routine implementation requires that the
* prototype appears here. The function should not be used by application
* writers.
*
* Removes the current co-routine from its ready list and places it in the
* appropriate delayed list.
*/
void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList );
 
/*
* This function is intended for internal use by the queue implementation only.
* The function should not be used by application writers.
*
* Removes the highest priority co-routine from the event list and places it in
* the pending ready list.
*/
signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList );
 
 
#endif /* CO_ROUTINE_H */
/trunk/sw/freertos-sample1/sample.c
0,0 → 1,70
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
 
#define PERIODO1 ( ( portTickType ) 1000 / portTICK_RATE_MS )
#define PERIODO2 ( ( portTickType ) 3000 / portTICK_RATE_MS )
#define PERIODO3 ( ( portTickType ) 100 / portTICK_RATE_MS )
 
unsigned int lectura_pot; /* para comunicarselo entre tareas */
 
/*-----------------------------------------------------------*/
static void vTask1( void *pvParameters )
{
unsigned marca;
/* The parameters are not used. */
( void ) pvParameters;
 
uart1_printline("\r\n\r\n");
marca = 0;
/* Cycle for ever, delaying then checking all the other tasks are still
operating without error. */
for( ;; )
{
switch(marca)
{
case 0 : uart1_printchar('-'); break;
case 1 : uart1_printchar('\\'); break;
case 2 : uart1_printchar('|'); break;
case 3 : uart1_printchar('/'); break;
}
uart1_printchar('\r');
marca++;
if(marca == 4) marca = 0;
vTaskDelay( PERIODO1 );
}
}
 
/*-----------------------------------------------------------*/
 
portSHORT main( void )
{
portBASE_TYPE xReturn;
uart1_printline("entering main()\r\n");
/* Create the tasks defined within this file. */
xReturn = xTaskCreate( vTask1, (const signed portCHAR *) "TSK1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
if(xReturn != pdPASS)
{
uart1_printline("xTaskCreate failed\r\n");
return 0;
}
/* In this port, to use preemptive scheduler define configUSE_PREEMPTION
as 1 in portmacro.h. To use the cooperative scheduler define
configUSE_PREEMPTION as 0. */
uart1_printline("starting scheduler....\r\n");
vTaskStartScheduler();
uart1_printline("end\r\n");
return 0;
}
/trunk/sw/freertos-sample1/Makefile
0,0 → 1,29
PRJ = sample
CRT = ../crt/crt-sram
SRCS = $(PRJ).c
OBJS = $(SRCS:.c=.o)
LINK = ../link/sp3sk-sram.ld
PATH_FREERTOS = ../freertos
 
$(PRJ).srec: $(PRJ).out
mb-objcopy -O srec $(PRJ).out $(PRJ).srec
mb-objcopy -O binary $(PRJ).out $(PRJ).bin
..\..\utils\bin2rom $(PRJ).bin $(PRJ).rom
 
$(OBJS): $(SRCS)
mb-gcc -O2 -I. -I$(PATH_FREERTOS) -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
 
$(PRJ).out: $(CRT).o $(OBJS)
mb-ld -L $(PATH_FREERTOS) -L ../lib -T $(LINK) -Map=$(PRJ).map -o $(PRJ).out $(CRT).o $(OBJS) -lfreertos -lgcc -lc -lm -lgcc -lio
clean:
-rm *.o
-rm *.out
-rm *.bin
-rm *.v
-rm *.map
-rm *.lst
-rm *.bak
-rm *.srec
-rm *.prom
-rm *.rom
/trunk/sw/monc/Makefile
14,10 → 14,10
..\..\utils\bin2rom $(PRJ).bin $(PRJ).rom
 
$(OBJS): $(SRCS)
mb-gcc -B. -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
mb-gcc -O2 -I . -I ../lib -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
 
$(PRJ).out: $(CRT).o $(OBJS)
mb-ld -T $(LINK) -Map=$(PRJ).map -o $(PRJ).out $(CRT).o $(OBJS)
mb-ld -L ../lib -T $(LINK) -Map=$(PRJ).map -o $(PRJ).out $(CRT).o $(OBJS) -lio
clean:
-rm *.o
/trunk/sw/monc/monc.c
9,21 → 9,9
d <hex32> <hex32> {1,2,4} --> dump starting at <hex32>, len=<hex32>, 1(bytes),2(halfw),4(words)
w <hex32> <hex32> {1,2,4} --> write at <hex32> value=<hex32> 1(byte), 2(halfw), 4(word)
f <hex32> <hex32> <hex32> --> fill starting at <hex32>, len=<hex32>, value=<hex32> (word)
---------------------------------------- */
 
#define UARTS_STATUS_PORT 0x08000004
#define UART1_TX_FULL 0x10
#define UART1_DATA_AVAILABLE 0x01
 
#define UART1_TXRX 0x08000008
 
#define PROM_DATA 0x08000010
#define PROM_CONTROL 0x08000011
#define REQUEST_SYNC 0x01
#define REQUEST_BYTE 0x02
#define IS_PROM_SYNCED 0x04
#define IS_DATA_AVAILABLE 0x08
 
---------------------------------------- */
#include "openfire.h"
#define SRAM_START 0x04000000
 
#define MAX_LINE 128
31,18 → 19,6
 
// -------------------------------------
 
void uart1_printchar(unsigned char);
void uart1_printline(char *);
char uart1_readchar(void);
void uart1_readline(char *);
 
unsigned gethexchar(char);
unsigned ishexdigit(char);
char *gethex(char *, unsigned *, unsigned);
 
char puthexchar(unsigned);
void puthexstring(char *, unsigned, unsigned);
 
void process_Sline(void);
void dump(unsigned, int, unsigned);
void write(unsigned, unsigned, unsigned);
80,9 → 56,9
case 'd' :
case 'w' :
case 'f' :
ptr = gethex(input_buffer + 2, &p1, 8); // start address
ptr = gethex(ptr + 1, &p2, 8); // lenght or value
ptr = gethex(ptr + 1, &p3, 8); // width=1,2,4 or value
ptr = gethexstring(input_buffer + 2, &p1, 8); // start address
ptr = gethexstring(ptr + 1, &p2, 8); // lenght or value
ptr = gethexstring(ptr + 1, &p3, 8); // width=1,2,4 or value
if(input_buffer[0] == 'd') dump(p1, p2, p3);
else if(input_buffer[0] == 'w') write(p1, p2, p3);
else fill(p1, p2, p3);
91,11 → 67,11
case 'S' : process_Sline();
break;
case 'l' : gethex(input_buffer + 2, &p1, 2); // file-id
case 'l' : gethexstring(input_buffer + 2, &p1, 2); // file-id
load_promfile(p1);
break;
case 'x' : gethex(input_buffer + 2, &p1, 8);
case 'x' : gethexstring(input_buffer + 2, &p1, 8);
((void (*)(void))p1)();
break;
}
102,84 → 78,6
goto main_loop;
}
 
// --------- uart #1 functions ----------
void uart1_printchar(unsigned char c)
{
while( (*(unsigned char *) UARTS_STATUS_PORT) & UART1_TX_FULL ); // wait empty buffer
*(char *) UART1_TXRX = c;
}
 
void uart1_printline(char *txt)
{
while( *(unsigned char *)txt ) uart1_printchar( (unsigned char) *(txt++));
}
 
char uart1_readchar(void)
{
while( ((*(unsigned char *) UARTS_STATUS_PORT) & UART1_DATA_AVAILABLE) == 0 ); // wait a received char
return *(char *) UART1_TXRX;
}
 
void uart1_readline(char *buffer)
{
char tmp;
do
{
*(buffer++) = tmp = uart1_readchar();
uart1_printchar(tmp);
} while(tmp != 0x0 && tmp != '\n' && tmp != '\r');
}
 
// ------------ ascii 2 hex -------------
unsigned gethexchar(char c)
{
if(c >= 'a') c = c - 'a' + '0' + 10;
else if(c >= 'A') c = c - 'A' + '0' + 10;
return c - '0';
}
 
unsigned ishexdigit(char c)
{
return (c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F');
}
 
char *gethex(char *string, unsigned *value, unsigned maxdigits)
{
unsigned number = 0;
while( ishexdigit( string[0] ) && maxdigits > 0)
{
number <<= 4;
number |= gethexchar(string[0]);
string++;
maxdigits--;
}
*value = number;
return string;
}
// ----------- hex 2 ascii ------------------
char puthexchar(unsigned n)
{
n &= 0xF;
return n + (n < 10 ? '0' : 'A' - 10);
}
 
void puthexstring(char *string, unsigned number, unsigned size)
{
int n = size - 1;
while(number && n >= 0) // hex 2 ascii right to left
{
string[n] = puthexchar(number & 0xf);
number >>= 4;
n--;
}
while(n >= 0) string[n--] = '0'; // left padding with 0
}
 
// --------------------------------------------------------------
// process S1, S2 and S3 records
// http://www.amelek.gda.pl/avr/uisp/srecord.htm
191,9 → 89,9
 
if(tipo < 1 || tipo > 3) return; // process 1, 2 or 3 records only
 
gethex(input_buffer + 2, &rec_len, 2); // number of bytes in the record (address+data+checksum)
gethexstring(input_buffer + 2, &rec_len, 2); // number of bytes in the record (address+data+checksum)
checksum += rec_len;
gethex(input_buffer + 4, &address, tipo == 1 ? 4 : (tipo == 2 ? 6 : 8) ); // read start address
gethexstring(input_buffer + 4, &address, tipo == 1 ? 4 : (tipo == 2 ? 6 : 8) ); // read start address
pos = 4 + 2 + (tipo << 1); // 1st byte of data is at...
rec_len -= tipo == 1 ? 2 : (tipo == 2 ? 3 : 4);
207,13 → 105,13
 
while(rec_len-- > 1) // read all data bytes and store in memory
{
gethex(input_buffer + pos, &byte, 2); // read byte
gethexstring(input_buffer + pos, &byte, 2); // read byte
*(unsigned char *)address++ = (unsigned char) byte;
checksum += byte;
pos += 2;
}
 
gethex(input_buffer + pos, &byte, 2); // read checksum
gethexstring(input_buffer + pos, &byte, 2); // read checksum
checksum += byte;
if( (checksum & 0xff) != 0xff) uart1_printline(error); // verify checksum
}
273,11 → 171,11
void load_promfile(unsigned file_id)
{
unsigned char *ptr = (unsigned char *)SRAM_START; // start of SRAM
unsigned char status, data;
unsigned long status, data;
unsigned fileno, size;
 
status = *(unsigned char *) PROM_CONTROL;
if( !(status & IS_PROM_SYNCED) ) // not in sync .. exit
status = *(volatile unsigned long *) PROM_READER;
if( !(status & PROM_SYNCED) ) // not in sync .. exit
{
uart1_printline(nofile);
return;
297,8 → 195,8
unsigned char prom_readbyte(void)
{
*(unsigned char *) PROM_CONTROL = REQUEST_BYTE; // request byte
while( !(*(unsigned char *) PROM_CONTROL & IS_DATA_AVAILABLE) ); // wait for data
*(unsigned char *) PROM_CONTROL = 0;
return *(unsigned char *) PROM_DATA; // return byte
*(unsigned long *) PROM_READER = PROM_REQUEST_DATA; // request byte
while( !(*(volatile unsigned long *) PROM_READER & PROM_DATA_READY) ); // wait for data
*(unsigned char *) PROM_READER = 0;
return (unsigned char) ((*(volatile unsigned long *) PROM_READER) & PROM_DATA);// return byte
}
/trunk/sw/vga/Makefile
2,7 → 2,7
CRT = ../crt/crt-sram
LIB = vga_5x7_fuente.c vga_5x7_putchar.c vga_5x7_putline.c vga_5x7_setfgcolor.c vga_5x7_setbgcolor.c vga_clearscreen.c vga_drawpixel.c
SRCS = $(PRJ).c $(LIB)
OBJS = $(SRCS:.c=.o) ../lib/uart1io.o
OBJS = $(SRCS:.c=.o)
LINK = ../link/sp3sk-sram.ld
 
$(PRJ).srec: $(PRJ).out
15,10 → 15,10
mb-ar q lib$(PRJ).a $(OBJS)
 
$(OBJS): $(SRCS)
mb-gcc -B. -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
mb-gcc -O2 -B. -mno-xl-soft-mul -c -Wa,-ahlms=$(@:.o=.lst) -o $@ $(@:.o=.c)
 
$(PRJ).out: $(CRT).o $(OBJS)
mb-ld -T $(LINK) -Map=$(PRJ).map -o $(PRJ).out $(CRT).o $(OBJS) -lgcc -lc -lm -lgcc
mb-ld -L ../lib -T $(LINK) -Map=$(PRJ).map -o $(PRJ).out $(CRT).o $(OBJS) -lgcc -lc -lm -lgcc -lio
clean:
-rm *.o

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.