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/uart1io.c
File deleted
/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-sram-with-int.s
File deleted
/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 |