Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
L
lpc43xx-hal
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Embedded Rust
lpc43xx-hal
Merge requests
!15
Queued uart can example
Code
Review changes
Check out branch
Download
Patches
Plain diff
Expand sidebar
Merged
Queued uart can example
Queued-UART-CAN-example
into
master
Overview
0
Commits
7
Pipelines
1
Changes
1
Merged
A Sundbom
requested to merge
Queued-UART-CAN-example
into
master
5 years ago
Overview
0
Commits
7
Pipelines
1
Changes
1
Merges the UART-CAN bridge example into master
0
0
Merge request reports
Compare
master
master (base)
and
latest version
latest version
0a0fbe09
7 commits,
5 years ago
1 file
+
388
−
0
Inline
Compare changes
Side-by-side
Inline
Show whitespace changes
Show one file at a time
examples/queued_can-uart_bridge.rs
0 → 100644
+
388
−
0
View file @ 0a0fbe09
Edit in single-file editor
Open in Web IDE
//! # CAN Bridge Example
//! Data recieved at CAN0 id 0x4B0 is sent to UART3 (19200 baud)
//! Data recieved from UART1 is sent as single bytes on CAN Id 0x530
//!
//! Tested with UART loopback (TX connected to Rx)
//! # Usage
//! On the host machine, send messages to the bridge using
//! ```
//! cansend slcan0 4b0#6162636465 ->
//!
//! candump:
//! slcan0 4B0 [5] 61 62 63 64 65
//! slcan0 530 [1] 61
//! slcan0 530 [1] 62
//! slcan0 530 [1] 63
//! slcan0 530 [1] 64
//! slcan0 530 [1] 65
//! ```
//!
//! PuTTy listen on Uart
//! abcde
//!
#![no_main]
#![no_std]
#[allow(unused_extern_crates)]
extern
crate
panic_halt
;
use
cortex_m
::
asm
;
use
rtfm
::
app
;
use
heapless
::{
self
,
consts
::
U32
,
spsc
::{
Consumer
,
Producer
,
Queue
},
};
use
embedded_hal
::
digital
::
v2
::{
OutputPin
,
ToggleableOutputPin
};
use
lpc43xx_hal
::{
io
::
pin
::{
split_ports
,
Gpio
,
IntoGpioPin
,
Input
,
Output
,
OpenDrain
,
OpenDrainPin
,
Pin
,
PinSplit
,
U1
,
U4
,
U5
,
U6
,
U3
,
U2
,
U10
,
Uninit
},
can
::{
CanBus
,
MsgIface
,
MsgObj
},
serial
::{
Read
,
Serial
,
Write
},
timer
::{
self
,
EMC0_A
,
MR0I_A
,
MR0R_A
,
MR0S_A
,
NoMatchPin
,
NoCapturePin
},
pac
::{
self
,
c_can1
::{
stat
::
LEC_A
,
cntl
::{
DAR_A
,
EIE_A
,
IE_A
,
SIE_A
},
},
usart0
::{
lcr
::{
BC_A
,
DLAB_A
,
PE_A
,
PS_A
,
SBS_A
,
WLS_A
},
iir
::{
INTID_A
,
INTSTATUS_A
},
},
SCU
,
},
};
type
Test0Timer
=
timer
::
Timer
<
pac
::
TIMER0
,
NoMatchPin
,
NoMatchPin
,
NoMatchPin
,
NoMatchPin
,
NoCapturePin
,
NoCapturePin
,
NoCapturePin
,
NoCapturePin
>
;
type
CanBridge
=
CanBus
<
pac
::
C_CAN0
,
heapless
::
consts
::
U32
>
;
type
UartBridge
=
Serial
<
pac
::
USART0
>
;
static
BLINK_PERIOD
:
u32
=
30384
;
static
STRING
:
[
u8
;
13
]
=
[
0x48
,
0x65
,
0x6c
,
0x6c
,
0x6f
,
0x20
,
0x77
,
0x6f
,
0x72
,
0x6c
,
0x64
,
0x21
,
0x20
,
];
/// Transmit data over UART
fn
send_over_can
(
can
:
&
mut
CanBridge
,
tx_obj
:
&
mut
MsgObj
,
val
:
u8
)
{
// Setup CAN TX data
tx_obj
.data_a1
(
val
,
0
);
// Set TX status
tx_obj
.msgval
(
true
)
.newdat
(
true
)
.mctrl_txrqst
(
true
);
// Transfer object to message RAM
can
.transfer_obj
(
MsgIface
::
Iface1
,
10
,
&
tx_obj
);
}
#[app(device
=
lpc43xx_pac)]
const
APP
:
()
=
{
static
mut
UART
:
UartBridge
=
();
static
mut
CAN_0
:
CanBridge
=
();
static
mut
TIMER
:
Test0Timer
=
();
static
mut
XRAY_TX_OBJ
:
MsgObj
=
();
static
mut
TO_XRAY_QUEUE
:
Queue
<
u8
,
heapless
::
consts
::
U64
>
=
();
static
mut
FROM_XRAY_QUEUE
:
Queue
<
u8
,
heapless
::
consts
::
U64
>
=
();
static
mut
IDX
:
u8
=
0
;
#[init]
fn
init
()
->
init
::
LateResources
{
// ============= TX/RX Queues ==============
let
to_xray_queue
:
Queue
<
u8
,
heapless
::
consts
::
U64
>
=
Queue
::
new
();
let
from_xray_queue
:
Queue
<
u8
,
heapless
::
consts
::
U64
>
=
Queue
::
new
();
// =========================================
// ================= Clock =================
// TODO: move me!
setup_clk
(
&
device
.CGU
);
// Set PLL1 on UART0
unsafe
{
device
.CGU.base_uart0_clk
.write
(|
w
|
w
.clk_sel
()
.bits
(
0x09
));
}
// =========================================
// ================= Pins ==================
device
.SCU.sfsp3_2
.write
(|
w
|
w
.mode
()
.function_2
());
//P1_17 CAN0_TD
device
.SCU.sfsp3_1
.write
(|
w
|
w
//P1_18 CAN0_RD
.mode
()
.function_2
()
.ezi
()
.enable_input_buffer
()
.zif
()
.disable_input_glitch_filter
()
);
// device.SCU.sfsp1_17.write(|w| w.mode().function_5()); //P1_17 CAN0_TD
// device.SCU.sfsp1_18.write(|w| w //P1_18 CAN0_RD
// .mode().function_5()
// .ezi().enable_input_buffer()
// .zif().disable_input_glitch_filter() );
// Configure Serial
let
ports
=
split_ports
(
device
.SCU
,
device
.GPIO_PORT
);
let
port_7
=
ports
.port_7
.split_pins
();
let
mut
can_stby
=
port_7
.p7_4
.into_gpio
()
.into_output
();
can_stby
.set_low
();
let
port_9
=
ports
.port_9
.split_pins
();
let
uart0_tx
=
port_9
.p9_5
;
let
uart0_rx
=
port_9
.p9_6
;
// =========================================
// ================= Timer =================
let
mut
t
=
Test0Timer
::
new_no_pins
(
device
.TIMER0
);
t
.start_timer
(
false
);
t
.set_match
(
0
,
BLINK_PERIOD
);
t
.set_prescaler
(
2048
,
Some
(
0
));
unsafe
{
t
.mr0
(
MR0I_A
::
INTERRUPT
,
MR0R_A
::
RESET
,
MR0S_A
::
NO_STOP
,
EMC0_A
::
NOP
);
}
t
.start_timer
(
true
);
// =========================================
// ================== CAN ==================
let
mut
can_0
=
CanBridge
::
new
(
device
.C_CAN0
);
can_0
.initialize
(
12_000_000
,
500000
,
IE_A
::
ENABLE_CAN_INTERRUPTS
,
SIE_A
::
DISABLE_STATUS_CHANGE_INTERRUPTS
,
EIE_A
::
ENABLE_ERROR_INTERRUPTS
,
DAR_A
::
ENABLED
,
false
,
);
// == Setup message objects
let
power_control_rx_obj
=
MsgObj
::
new_rx_obj
(
true
,
0x6b0
,
0x2
,
0xfffffff
);
can_0
.transfer_obj
(
MsgIface
::
Iface1
,
13
,
&
power_control_rx_obj
);
let
to_x_ray_rx_obj
=
MsgObj
::
new_rx_obj
(
true
,
0x4b0
,
0x8
,
0xfffffff
);
can_0
.transfer_obj
(
MsgIface
::
Iface1
,
9
,
&
to_x_ray_rx_obj
);
let
mut
from_x_ray_tx_obj
=
MsgObj
::
new_tx_obj
(
true
,
0x530
,
0x1
,
0
,
0
);
from_x_ray_tx_obj
.data_a
(
true
);
from_x_ray_tx_obj
.data_b
(
true
);
// =========================================
// ================ USART ==================
let
mut
serial
=
UartBridge
::
new
(
device
.USART0
,
uart0_tx
,
uart0_rx
,
0x98
,
0x02
,
0x0
);
//.. DLL=0x41, DLM, Trigger)
//DLL 0x91, DLH 0x01 PCLK 126MHz -> 19200 baud
//DLL 0x98, DLH 0x02, PCLK 204MHz -> 19200 baud
serial
.lcr
(
WLS_A
::
_8_BIT_CHARACTER_LENGTH
,
SBS_A
::
_1_STOP_BIT
,
PE_A
::
DISABLE_PARITY_GENERERATION
,
PS_A
::
ODD_PARITY
,
BC_A
::
DISABLED
,
DLAB_A
::
DISABLED
,
);
serial
.ier
(
true
,
true
,
false
,
false
,
false
);
serial
.reset_rx_fifo
();
serial
.reset_tx_fifo
();
// =========================================
init
::
LateResources
{
TO_XRAY_QUEUE
:
to_xray_queue
,
FROM_XRAY_QUEUE
:
from_xray_queue
,
UART
:
serial
,
TIMER
:
t
,
CAN_0
:
can_0
,
XRAY_TX_OBJ
:
from_x_ray_tx_obj
,
}
}
#[interrupt(resources
=
[
CAN_0,
XRAY_TX_OBJ,
TO_XRAY_QUEUE,
IDX,
TIMER,
UART]
)]
fn
TIMER0
()
{
*
resources
.IDX
=
(
*
resources
.IDX
+
1
)
%
13
;
//Clear interrupt
resources
.TIMER
.clear_interrupt
(
timer
::
InterruptType
::
MatchChannel
,
0
);
}
#[interrupt(resources
=
[
CAN_0,
XRAY_TX_OBJ,
FROM_XRAY_QUEUE,
TO_XRAY_QUEUE,
UART]
)]
fn
USART0
()
{
// Get interrupt info
let
(
int_status
,
int_id
)
=
resources
.UART
.read_iir
();
match
int_id
{
INTID_A
::
RDA
=>
{
// Data available
let
queue_was_empty
=
resources
.FROM_XRAY_QUEUE
.len
()
==
0
;
// Read a single byte from UART and place on CAN TX queue
let
val
=
resources
.UART
.read
()
.unwrap
();
match
resources
.FROM_XRAY_QUEUE
.enqueue
(
val
)
{
Ok
(
_
)
=>
(),
Err
(
_
)
=>
asm
::
bkpt
(),
}
if
queue_was_empty
{
match
resources
.FROM_XRAY_QUEUE
.dequeue
()
{
None
=>
(),
Some
(
val
)
=>
send_over_can
(
&
mut
*
resources
.CAN_0
,
&
mut
*
resources
.XRAY_TX_OBJ
,
val
),
}
}
},
INTID_A
::
THRE
=>
{
// USART TX queue ready for data
if
resources
.TO_XRAY_QUEUE
.len
()
>
0
{
match
resources
.TO_XRAY_QUEUE
.dequeue
()
{
None
=>
(),
Some
(
i
)
=>
{
resources
.UART
.write
(
i
)
.unwrap
();
}
}
}
},
_
=>
(),
}
}
#[interrupt(resources
=
[
CAN_0,
XRAY_TX_OBJ,
UART,
TO_XRAY_QUEUE,
FROM_XRAY_QUEUE]
)]
fn
C_CAN0
()
{
// Get interrupt ID
let
intid
:
u16
=
resources
.CAN_0
.read_intid
();
match
resources
.CAN_0
.receive_obj
(
MsgIface
::
Iface1
)
{
Ok
(
res
)
=>
match
intid
{
9
=>
{
// Receive from UART
let
data_length
=
res
.len
();
let
queue_was_empty
=
resources
.TO_XRAY_QUEUE
.len
()
==
0
;
for
data_num
in
0
..
data_length
{
//0..5 -> 0,1,2,3,4
let
the_byte
=
res
[
data_num
];
// Send byte from CAN to UART
match
resources
.TO_XRAY_QUEUE
.enqueue
(
the_byte
)
{
Ok
(
_
)
=>
(),
Err
(
_
)
=>
asm
::
bkpt
(),
}
}
// Dequeue and write to UART
if
queue_was_empty
{
match
resources
.TO_XRAY_QUEUE
.dequeue
()
{
None
=>
(),
Some
(
i
)
=>
{
resources
.UART
.write
(
i
)
.unwrap
();
}
}
}
},
10
=>
{
// Send to UART
if
resources
.FROM_XRAY_QUEUE
.len
()
>
0
{
match
resources
.FROM_XRAY_QUEUE
.dequeue
()
{
None
=>
(),
Some
(
val
)
=>
send_over_can
(
&
mut
*
resources
.CAN_0
,
&
mut
*
resources
.XRAY_TX_OBJ
,
val
),
}
}
},
_
=>
(),
}
Err
(
u
)
=>
match
u
{
Ok
(
status
)
=>
{
let
lec
=
resources
.CAN_0.can.stat
.read
()
.lec
()
.variant
();
match
lec
{
LEC_A
::
ACKERROR_THE_MESSAG
=>
{
asm
::
bkpt
()
},
LEC_A
::
NO_ERROR
=>
{},
_
=>
{
asm
::
bkpt
()
}
}
},
Err
(
err
)
=>
(),
},
}
}
};
pub
fn
setup_clk
(
cgu
:
&
lpc43xx_pac
::
CGU
){
unsafe
{
// 204 MHz setup, direct mode
// Select the IRC as BASE_M4_CLK source
cgu
.base_m4_clk
.write
(|
w
|
w
.clk_sel
()
.bits
(
0x1
));
// Enable the crystal oscillator
cgu
.xtal_osc_ctrl
.modify
(|
_
,
w
|
w
.hf
()
.bit
(
false
));
cgu
.xtal_osc_ctrl
.modify
(|
_
,
w
|
w
.enable
()
.bit
(
false
));
// Wait 250us
for
i
in
0
..
3_000
{
core
::
ptr
::
read_volatile
(
&
i
);
}
cgu
.pll1_ctrl
.write
(|
w
|
{
w
.pd
()
.bit
(
false
)
.clk_sel
()
.bits
(
0x6
)
// Select the crystal oscillator as clock source
.msel
()
.bits
(
16
)
//16 => M=17
.nsel
()
.bits
(
0
)
// 0 => N=1
.psel
()
.bits
(
0
)
// 0 => P=1
.fbsel
()
.bit
(
true
)
//true => output feedback
.bypass
()
.bit
(
false
)
// 0=> normal PLL
.direct
()
.bit
(
true
)
// 0=> use post-divider
//=> no post divider => direct mode
// Clk = M * COSC/N
// CCO = CLK = 204 MHz
//156MHz < CCO < 320 MHz => OK
});
// Wait for the PLL to lock
while
!
cgu
.pll1_stat
.read
()
.lock
()
.bit
()
{}
// Select PLL1 as base_m4_clk source
cgu
.base_m4_clk
.modify
(|
_
,
w
|
w
.clk_sel
()
.bits
(
0x09
));
// Wait for 50us
for
i
in
0
..
600
{
core
::
ptr
::
read_volatile
(
&
i
);
}
}
}
Loading