[uquote="sunjob",url="/forum/viewtopic.php?p=4794259#p4794259"]посмотрел цены в борзом чиппо-диппе, и действительно, даже там цены очень интересные.[/uquote]
Я когда году в 2013-м купил первый STM32, простенький 20-ти ногий F0, там уже SPI с FIFO был, а если вы посмотрите на флагмана от Artery, то там FIFO нет ни в SPI, ни в USART, ни в DMA. У старенького STM32F4 DMA уже более новый, правда тогда еще DMAMUX не было. Т.е. если сравнивать Artery с F4, будет где-то лучше, где-то хуже, а если сравнивать с чем-то современным и схожим по производительности, типа STM32H5, то это вообще не сравнимые вещи, не только по периферии, но я новые ядра Artery тоже еще не осилил. Касательно документации... Документация на китайские мк всегда хуже, если, для примера, возьмем тот же AT32F407 DMA, где уже интегрирован DMAMUX, то в RM описание занимает 16 страниц, а такой же DMA у STM32 + DMAMUX занимает 38. Дополнительно для STM32 можно списать аппноуты практически на всю периферию, иногда по несколько на каждую. Плюс есть книги, "STM32 Online Training" со слайдами и видео, наконец "STM32 Workshop" на youtube канале ST. Для Artery в разделе "Application Note" я вижу 4 документа один из которых Errata, для STM32H5 таковых 64 и Errata тужа даже не входит.
Добавлено after 9 minutes 14 seconds:
[uquote="linux_rulezz",url="/forum/viewtopic.php?p=4794402#p4794402"]Правда, сходу USB у меня не заработал: хардфолт в прерывании, ну, почитаю документацию: видимо, адреса буферов перенесли, засранцы…[/uquote]
Там все несколько сложнее ) Надергал у себя основные отличия:
Спойлер
Код: Выделить всё
#if defined(STM32F3)
using PmaWidth = uint32_t; // F1/F3
#else
using PmaWidth = uint16_t; // G4/F0/L0
#endif
#ifdef STM32G0
static auto USB = USB_DRD_FS;
static constexpr uint32_t USB_EP_CTR_RX = USB_EP_VTRX;
static constexpr uint32_t USB_EP_CTR_TX = USB_EP_VTTX;
static constexpr uint32_t USB_ISTR_EP_ID = USB_ISTR_IDN;
static constexpr uint32_t USB_EPREG_MASK = USB_CHEP_REG_MASK;
static constexpr uint32_t USB_EPTX_DTOGMASK = USB_CHEP_TX_DTOGMASK;
static constexpr uint32_t USB_EPRX_DTOGMASK = USB_CHEP_RX_DTOGMASK;
static constexpr uint32_t USB_CNTR_FSUSP = USB_CNTR_SUSPEN;
static constexpr uint32_t USB_CNTR_LPMODE = USB_CNTR_SUSPRDY;
static constexpr uint32_t USB_PMAADDR = USB_DRD_PMAADDR;
static constexpr uint32_t USB_CNTR_FRES = USB_CNTR_USBRST;
#else
struct EpBufDesc
{
volatile PmaWidth addrTx;
volatile PmaWidth countTx;
volatile PmaWidth addrRx;
volatile PmaWidth countRx;
};
#endif
#ifdef STM32G0
static auto pmaBuf(uint32_t epNum) { return USB_DRD_PMA_BUFF + epNum; }
static volatile uint32_t& epnr(uint32_t epNum) { return (&USB->CHEP0R)[epNum]; }
static void setTxAddr(uint32_t epNum, uint32_t addr) { ModifyReg(pmaBuf(epNum)->TXBD, ~USB_PMA_TXBD_ADDMSK, addr); }
static void setTxCnt(uint32_t epNum, uint32_t count) { ModifyReg(pmaBuf(epNum)->TXBD, ~USB_PMA_TXBD_COUNTMSK, count << 16); }
static void setRxAddr(uint32_t epNum, uint32_t addr) { ModifyReg(pmaBuf(epNum)->RXBD, ~USB_PMA_RXBD_ADDMSK, addr); }
static void setRxCnt(uint32_t epNum) { ModifyReg(pmaBuf(epNum)->RXBD, ~USB_PMA_RXBD_COUNTMSK, 0x8400'0000); }
static uint32_t getTxCnt(uint32_t epNum) { return (pmaBuf(epNum)->TXBD >> 16) & 0x03FF; }
static uint32_t getRxCnt(uint32_t epNum)
{
volatile uint32_t count = 10;
while (count > 0) count = count - 1; // WA: few cycles for RX PMA descriptor to update
return (pmaBuf(epNum)->RXBD >> 16) & 0x03FF;
}
#else
static auto pmaBuf(uint32_t epNum) { return (EpBufDesc*)USB_PMAADDR + epNum; }
static volatile uint16_t& epnr(uint32_t epNum) { return (&USB->EP0R)[epNum * 2]; }
static void setTxAddr(uint32_t epNum, uint32_t addr) { pmaBuf(epNum)->addrTx = addr; }
static void setTxCnt(uint32_t epNum, uint32_t count) { pmaBuf(epNum)->countTx = count; }
static void setRxAddr(uint32_t epNum, uint32_t addr) { pmaBuf(epNum)->addrRx = addr; }
static void setRxCnt(uint32_t epNum) { pmaBuf(epNum)->countRx = 0x8400; } // 64 байта
static uint32_t getTxCnt(uint32_t epNum) { return pmaBuf(epNum)->countTx & 0x3FF; }
static uint32_t getRxCnt(uint32_t epNum) { return pmaBuf(epNum)->countRx & 0x3FF; }
#endif
#ifdef STM32G0
static void writePma(uint8_t* buf, uint32_t pmaBufAddr, uint32_t length)
{
auto pVal = (volatile uint32_t*)(USB_DRD_PMAADDR + pmaBufAddr);
for (uint32_t words = length / 4; words != 0; words--)
{
*pVal++ = unalignedRead<uint32_t>(buf);
buf += 4;
}
if (uint32_t bytes = length % 4; bytes != 0)
{
uint32_t val = 0;
buf += bytes;
while (bytes--)
{
val = (val << 8) | *(--buf);
}
*pVal = val;
}
}
#else
static void writePma(uint8_t* buf, uint32_t pmaBufAddr, uint32_t length)
{
static constexpr uint32_t pmaAccess = sizeof(PmaWidth) / 2;
auto pVal = (volatile uint16_t*)(USB_PMAADDR + pmaBufAddr * pmaAccess);
for (uint32_t i = (length + 1) / 2; i != 0; i--)
{
*pVal = buf[0] | (buf[1] << 8);
buf += 2;
pVal += pmaAccess;
}
}
#endif
#ifdef STM32G0
static void readPma(uint8_t* buf, uint32_t pmaBufAddr, uint32_t length)
{
auto pVal = (volatile uint32_t*)(USB_DRD_PMAADDR + pmaBufAddr);
for (uint32_t words = length / 4; words != 0; words--)
{
unalignedWrite<uint32_t>(buf, *pVal++);
buf += 4;
}
uint32_t val = *pVal;
for (uint32_t bytes = length % 4; bytes--;)
{
*buf++ = uint8_t(val);
val >>= 8;
}
}
#else
static void readPma(uint8_t* buf, uint32_t pmaBufAddr, uint32_t length)
{
static constexpr uint32_t pmaAccess = sizeof(PmaWidth) / 2;
auto pVal = (volatile uint16_t*)(USB_PMAADDR + pmaBufAddr * pmaAccess);
for (uint32_t i = length / 2; i != 0; i--)
{
unalignedWrite<uint16_t>(buf, *pVal);
buf += 2;
pVal += pmaAccess;
}
if (length % 2) *buf = uint8_t(*pVal);
}
#endif
Еще при инициализации для G0 нужно добавить:
Код: Выделить всё
USB->BTABLE = 0;
PWR->CR2 |= PWR_CR2_USV; // USB supply enable