24.01.08 최초 작성
동기식 통신 방법으로 마스터와 슬레이브 모드로 동작
속도 제한이 없어 빠름
CS
를 통해 subnode
구분
SPI CLK, SCLK | CS | MOSI | MISO |
---|---|---|---|
Clock | Chip Select | Main out, Subnode in | Main in, Subnode out |
타켓 디바이스에 맞는 모드로 설정해야 함
CS
에 전원이 인가되지 않을 때 동작
SPI Mode 0 | SPI Mode 1 | SPI Mode 2 | SPI Mode 3 | |
---|---|---|---|---|
clock idle | low | low | high | high |
Rising edge일 때 data 읽음 | MOSI | MISO | MOSI | MISO |
Falling edge일 때 data 읽음 | MISO | MOSI | MISO | MOSI |
/driver/spi
에 위치하며 보드마다 다른 코드 사용
spi_controller
표준 인터페이스의 함수 포인터에 등록해 사용
.dtsi
파일이 존재해 부팅 시 SOC에 맞는 드라이버가 등록됨
/arch/arm/boot/dts/bcm2711.dtsi
: brcm,bcm2835-spi
와 매칭되는 디바이스 드라이버를 찾아 .probe
함수 실행 시킴...
spi3: spi@7e204600 {
compatible = "brcm,bcm2835-spi";
reg = <0x7e204600 0x0200>;
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clocks BCM2835_CLOCK_VPU>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
...
/drivers/spi/spi-bcm2835.c
: brcm,bcm2835-spi
와 매칭되는 디바이스 드라이버
...
static const struct of_device_id bcm2835_spi_match[] = {
{ .compatible = "brcm,bcm2835-spi", },
{}
};
MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
static struct platform_driver bcm2835_spi_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = bcm2835_spi_match,
},
.probe = bcm2835_spi_probe,
.remove = bcm2835_spi_remove,
.shutdown = bcm2835_spi_shutdown,
};
user레벨에서 SPI통신을 조작(속도 조절 등)할 수 있는 인터페이스 존재
/dev/spidev0.0
을 통해 조작 가능하며 해당 파일을 통해 조작할지 디바이스 드라이버를 조작할지 디바이스 트리에서 결정 가능
/arch/arm/boot/dts/bcm2711.dtsi
에 설정된 spi 디바이스 드라이버의 속성을 무시하기 위해 disable_spidev.dts
파일을 boot
파티션의 overlay
에 저장...
&spi0 {
pinctrl-names = "default";
pinctrl-0 = <&spi0_pins &spi0_cs_pins>;
cs-gpios = <&gpio 8 1>, <&gpio 7 1>;
spidev0: spidev@0{
compatible = "spidev";
reg = <0>; /* CE0 */
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <125000000>;
};
spidev1: spidev@1{
compatible = "spidev";
reg = <1>; /* CE1 */
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <125000000>;
};
};
...
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2708";
fragment@0 {
target = <&spidev0>;
__overlay__ {
status = "disabled";
};
};
};
k_spi.c
: 디바이스 ID를 출력#define TOY_SPI_BUS_NUM 0
struct spi_board_info spi_device_info = {
.modalias = "bmp280", //장치 이름
.max_speed_hz = 1000000, //통신 속도
.bus_num = TOY_SPI_BUS_NUM, //0번 spi interface 사용
.chip_select = 0, //cs번호 지정
.mode = 3, //spi 통신 모드 설정
};
k_module_init()
: static int __init k_module_init(void)
{
...
master = spi_busnum_to_master(TOY_SPI_BUS_NUM); //spi통신에서 master의 정보 가져옴
if (!master) {
pr_err("Error! spi bus with Nr. %d\n", TOY_SPI_BUS_NUM);
goto reg_error;
}
bmp280_dev = spi_new_device(master, &spi_device_info); //디바이스 정보를 입력받아 장치를 조작할
//수 있는 인터페이스 생성
if(!bmp280_dev) {
pr_info("Could not spi create device!\n");
goto reg_error;
}
bmp280_dev->bits_per_word = 8; //word 설정
if(spi_setup(bmp280_dev) != 0){ //디바이스 인터페이스 초기화
pr_info("Could not change bus setup!\n");
spi_unregister_device(bmp280_dev);
goto spi_error;
}
id = spi_w8r8(bmp280_dev, 0xD0); //디바이스의 ID 읽어옴
pr_info("ID: 0x%x\n", id);
return 0;
...
}
disable_spidev.dtbo
, k_spi.ko
생성
boot
디렉토리 마운트하고 disable_spidev.dtbo
를 /boot/overlays
에 옮김
/boot/config.txt
에 dtoverlay=disable_spidev
, dtparam=spi=on
입력, 저장 후 재부팅
modprobe spi_bcm2835
실행
insmod k_spi.ko
로 디바이스 드라이버 등록
핀 설정 확인
mount -t debugfs debugfs /sys/kernel/debug
cd /sys/kernel/debug
cat pinctrl/pinctrl-maps