-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathspi_dma.cpp
97 lines (83 loc) · 2.2 KB
/
spi_dma.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
* author : Shuichi TAKANO
* since : Sun Aug 25 2019 15:33:59
*/
#include "spi_dma.h"
#include <dmac.h>
#include <utils.h>
#include <sysctl.h>
#include <spi.h>
#include <fpioa.h>
SPIDMA &SPIDMA::instance()
{
static SPIDMA inst;
return inst;
}
void SPIDMA::init(spi_device_num_t spiNum,
dmac_channel_number_t dmaCh,
int ssPin, int ss, int prio)
{
spiNum_ = spiNum;
volatile spi_t *const spi[4] =
{
(volatile spi_t *)SPI0_BASE_ADDR,
(volatile spi_t *)SPI1_BASE_ADDR,
(volatile spi_t *)SPI_SLAVE_BASE_ADDR,
(volatile spi_t *)SPI3_BASE_ADDR,
};
spi_ = spi[spiNum];
cs_ = (spi_chip_select_t)(SPI_CHIP_SELECT_0 + ss);
dmaCh_ = dmaCh;
priority_ = prio;
fpioa_set_function(ssPin, (fpioa_function_t)(FUNC_SPI0_SS0 + ss));
}
void SPIDMA::waitDone()
{
dmac_wait_done(dmaCh_);
}
void SPIDMA::waitIdle()
{
dmac_wait_idle(dmaCh_);
}
int SPIDMA::irqEntry(void *ctx)
{
((SPIDMA *)ctx)->irq();
return 0;
}
void SPIDMA::irq()
{
dmac_irq_unregister(dmaCh_);
#if 0
while ((spi_->sr & 0x05) != 0x04)
;
spi_->ser = 0x00;
spi_->ssienr = 0x00;
#endif
if (callback_)
{
callback_();
}
}
void SPIDMA::_setupTransfer()
{
spi_init(spiNum_, SPI_WORK_MODE_0, SPI_FF_OCTAL, 32, 0);
spi_init_non_standard(spiNum_, 0 /*instrction length*/, 32 /*address length*/, 0 /*wait cycles*/,
SPI_AITM_AS_FRAME_FORMAT /*spi address trans mode*/);
set_bit(&spi_->ctrlr0, 3 << 8, SPI_TMOD_TRANS << 8);
spi_->dmacr = 0x2; /*enable dma transmit*/
spi_->ssienr = 0x01;
sysctl_dma_select((sysctl_dma_channel_t)dmaCh_, SYSCTL_DMA_SELECT_SSI0_TX_REQ);
}
void SPIDMA::_transferBE(const uint32_t *data, uint32_t count)
{
dmac_irq_register(dmaCh_, irqEntry, this, priority_);
dmac_set_single_mode(dmaCh_, data, (void *)(&spi_->dr[0]), DMAC_ADDR_INCREMENT, DMAC_ADDR_NOCHANGE,
DMAC_MSIZE_4, DMAC_TRANS_WIDTH_32, count);
spi_->ser = 1U << cs_;
}
// Big Endianでデータを転送する
void SPIDMA::transferBE(const uint32_t *data, uint32_t count)
{
_setupTransfer();
_transferBE(data, count);
}