(This is an 8-bit version, please switch to the corresponding branch for the 32-bit version.)
CDBUS is a protocol for Asynchronous Serial Communication,
it has a 3-byte header: [src_addr, dst_addr, data_len]
, then user data, and finally 2 bytes of CRC.
It's suitable for one-to-one communication, e.g. UART or RS232.
In this case, the address for each side are usually carefully selected and fixed,
e.g: [0x55, 0xaa, data_len, ...]
, and the backward is: [0xaa, 0x55, data_len, ...]
.
The CDBUS protocol is more valuable for bus communication, e.g. RS485 or Single Line UART. In this case:
- It introduces an arbitration mechanism that automatically avoids conflicts like the CAN bus.
- Support dual baud rate, provide high speed communication, the baud rate in the data phase is up to:
sys_freq
÷ 3. - Supports unicast, multicast and broadcast.
- Max payload data size is 253 byte (you can increase it to 255 byte, but not recommended).
- Hardware packing, unpacking, verification and filtering, save your time and CPU usage.
- Backward compatible with traditional RS485 hardware (still retains arbitration function).
The protocol example timing, include only one byte user data:
(How long to enter idle and how long to allow sending can be set.)
Tips:
- When high-priority node send unimportant data, the transmission wait time (TX_PERMIT_LEN) can be dynamically increased.
Arbitration example:
In CDBUS-A mode, if the low-speed part takes a lot of time, it will be a communication efficiency bottleneck.
In this case, single-rate peer-to-peer bus communication can be implemented by CDBUS-BS mode:
- Configure different TX_PERMIT_LEN parameters for each node, and the difference should be sufficient to avoid conflicts.
- If any node has pending tx frame before TX-permit point, then start sent at the TX-permit point.
- Or wait for the idle time to exceed the MAX_IDLE_LEN, then send a break character to bring the bus out of idle mode.
The CDBUS-BS mode is suitable for high-speed applications with few nodes and is also suitable for software implementation.
Register Name | Addr | Access | Default | Description | Remarks |
---|---|---|---|---|---|
VERSION | 0x00 | RD | 0x0c | Hardware version | |
SETTING | 0x02 | RD/WR | 0x10 | Configs | |
IDLE_WAIT_LEN | 0x04 | RD/WR | 0x0a | How long to enter idle | Bit 7~0 |
TX_PERMIT_LEN_L | 0x05 | RD/WR | 0x14 | How long to allow sending | Bit 7~0 |
TX_PERMIT_LEN_H | 0x06 | RD/WR | 0x00 | Bit 9~8 | |
MAX_IDLE_LEN_L | 0x07 | RD/WR | 0xc8 | Max idle for BS mode | Bit 7~0 |
MAX_IDLE_LEN_H | 0x08 | RD/WR | 0x00 | Bit 9~8 | |
TX_PRE_LEN | 0x09 | RD/WR | 0x01 | Active TX_EN before TX | Bit 1~0, not used in arbitration mode |
FILTER | 0x0b | RD/WR | 0xff | Set to local address | |
DIV_LS_L | 0x0c | RD/WR | 0x5a | Low-speed rate setting | Bit 7~0 |
DIV_LS_H | 0x0d | RD/WR | 0x01 | Bit 15~8 | |
DIV_HS_L | 0x0e | RD/WR | 0x5a | High-speed rate setting | If not use dual rate, set the same value as DIV_LS |
DIV_HS_H | 0x0f | RD/WR | 0x01 | ||
INT_FLAG | 0x10 | RD | n/a | Status | |
INT_MASK | 0x11 | RD/WR | 0x00 | Interrupt mask | |
RX | 0x14 | RD | n/a | Read RX page | |
TX | 0x15 | WR | n/a | Write TX page | |
RX_CTRL | 0x16 | WR | n/a | RX control | |
TX_CTRL | 0x17 | WR | n/a | TX control | |
RX_ADDR | 0x18 | RD/WR | 0x00 | RX page read pointer | Rarely used |
RX_PAGE_FLAG | 0x19 | RD | n/a | RX page flag | For debugging |
FILTER1 | 0x1a | RD/WR | 0xff | Multicast filter1 | |
FILTER2 | 0x1b | RD/WR | 0xff | Multicast filter2 |
SETTING:
FIELD | DESCRIPTION |
---|---|
[0] | Enable push-pull output for tx and tx_en pin |
[1] | Invert tx output |
[2] | CRC maintained by user |
[3] | Save broken frame |
[4] | Enable arbitration |
[5] | Break Sync mode |
[6] | Full duplex mode |
[4] | [5] | [6] | DESCRIPTION |
---|---|---|---|
1 | 0 | 0 | CDBUS-A mode (default) |
0 | 1 | 0 | CDBUS-BS mode |
0 | 0 | 1 | Full-duplex mode |
0 | 0 | 0 | Traditional half-duplex mode |
FILTERS:
Match from top to bottom:
SRC_ADDR | DST_ADDR | FILTER | FILTERn | Receive or drop | Remarks |
---|---|---|---|---|---|
not care | not care | 255 | not care | Receive | Promiscuous mode |
= FILTER | not care | != 255 | not care | Drop | Avoid loopback |
!= FILTER | 255 | not care | not care | Receive | Broadcast |
!= FILTER | != 255 | not care | any = DST_ADDR | Receive | Multicast |
!= FILTER | != 255 | = DST_ADDR | not care | Receive | Unicast |
not care | != 255 | != DST_ADDR | all != DST_ADDR | Drop |
It is recommended to reserve the address from 0xe0
to 0xfe
as the multicast address.
The default value 0xff of FILTERn means not enabled.
DIV_xx_x:
Baud rate divider value: DIV_xx[15:0] = sys_freq ÷ baud_rate − 1
The minimum value is 2.
INT_FLAG:
FIELD | DESCRIPTION |
---|---|
[0] | 1: Bus in IDLE mode |
[1] | 1: RX page ready for read |
[2] | 1: Receive break character |
[3] | 1: RX lost: no empty page for RX |
[4] | 1: RX error: frame broken |
[5] | 1: TX page released by hardware |
[6] | 1: TX collision detected |
[7] | 1: TX error: tx is 0, but rx is 1 |
INT_MASK:
Output of irq = ((INT_FLAG & INT_MASK) != 0).
RX_CTRL:
FIELD | DESCRIPTION |
---|---|
[0] | Reset RX page read pointer |
[1] | Switch RX page |
[2] | Clear RX lost flag |
[3] | Clear RX error flag |
[4] | Reset RX block |
[5] | Clear RX break flag |
TX_CTRL:
FIELD | DESCRIPTION |
---|---|
[0] | Reset TX page write pointer |
[1] | Switch TX page |
[2] | Clear TX collision flag |
[3] | Clear TX error flag |
[4] | Abort TX |
[5] | Send break character (for full-duplex and traditional mode) |
RX_PAGE_FLAG:
Value zero indicate the frame in current RX page is correct;
Non-zero indicate the pointer of last received byte of the disturbed frame, include CRC.
parameter DIV_LS = 346, // default: 115200 bps for 40MHz clk
parameter DIV_HS = 346
input clk, // core clock
input reset_n, // asynch active low reset
input chip_select, // reduce ram_rx power consumption
output irq, // interrupt output
// avalon-mm slave interface, read and write without latency
// support burst read and write (normally for REG_TX and REG_RX)
input [4:0] csr_address,
input csr_read,
output [7:0] csr_readdata,
input csr_write,
input [7:0] csr_writedata,
// connect to external PHY chip, e.g. MAX3485
input rx,
output tx,
output tx_en
# Configuration
write(REG_SETTING, [0x11]) # Enable push-pull output
# TX
write(REG_TX, [0x0c, 0x0d, 0x01, 0xcd]) # Write frame without CRC
while (read(REG_INT_FLAG) & 0x20) == 0: # Make sure we can successfully switch to the next page
pass
write(REG_TX_CTRL, [0x03]) # Trigger send by switching TX page
# RX
while (read(REG_INT_FLAG) & 0x02) == 0: # Wait for RX page ready
pass
header = read(REG_RX, len=3)
data = read(REG_RX, len=header[2])
write(REG_RX_CTRL, [0x03]) # Finish read by switching RX page
Install iverilog
(>= v10) and cocotb
, goto tests/
folder, then type the command:
$ COCOTB=/path/to/cocotb make
Then you can checkout the waveform cdbus.vcd
by GTKWave.
The CDCTL controller family uses the CDBUS IP Core, which provide SPI, I2C and PCIe peripheral interfaces.
E.g. The tiny CDCTL-Bx module support SPI and I2C interfaces:
For more information, visit: http://dukelec.com
This Source Code Form is subject to the terms of the Mozilla
Public License, v. 2.0. If a copy of the MPL was not distributed
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
Notice: The scope granted to MPL excludes the ASIC industry.
The CDBUS protocol is royalty-free for everyone except chip manufacturers.
Copyright (c) 2017 DUKELEC, All rights reserved.