QUOTE
но наличие вменяемого параллельного порта с ДМА, у stm да и у lpc вроде не заметил, ткните носом если не сложно.
Ну вот на примере LPC17xx - настраиваете DMA на передачу память-периферия, с инкрементом источника (это указатель на буфер) и с адресом приемника - адресом обычного GPIO. А в качестве источника запроса используете MATx.x
Вот пример (тут, правда, по таймеру в SPI выдается, но никто не мешает заменить регистр на GPIO)
CODE
unsigned short *TX_DMA_P=TX_outbuf0;
//TXSIZE
//Souce burst size=1
//Destination burst size=1
//Source transfer width=16-bit
//Destination transfer width=16-bit
//Source increment=1
//Destination increment=0
//Terminal count interrupt enable bit=1
#define TX_DMA_START_VALUE_CTRL (((TX_SIZE*3)<<0)+(0UL<<12)+(0UL<<15)+(1UL<<18)+(1UL<<21)+(1UL<<26)+(0UL<<27)+(1UL<<31))
//Enable, Source ignored, Destination - MAT1.0, memory to peripheral, ITC=1
#define TX_DMA_START_VALUE_CONF ((1UL<<0)+(10UL<<1)+(10UL<<6)+(1UL<<11)+(1UL<<15))
//Обработчик DMA, вызывается по концу передачи буфера в ЦАП
//Запускает следующий сегмент данных и стартует задачу передатчика
void GPDMA_IRQHandler(void)
{
UREG intf=DMACINTSTATUS;
if (intf&1)
{
//Прерывание от канала 0, передатчик
DMACINTTCCLEAR=1; //Сбрасываем флаг прерываний
DMACC0SRCADDR=(unsigned long)TX_DMA_P; //Откуда
DMACC0CONTROL=TX_DMA_START_VALUE_CTRL; //Размер и прочее
DMACC0CONFIGURATION=TX_DMA_START_VALUE_CONF; //Старт тут
NVIC_SetPend(NVIC_TIMER2); //Стартуем TMR2_IRQHandler - основной код передатчика
}
}
void InitTX(void)
{
DEBUG_PUTS("TX: Init timer for samples (~130.2kHz).\r\n");
T1MCR=2/*+1*/; //MR0I(выключен)+MR0R(включен)
T1MR0=768/3-1; //100MHz/(3*256)=130.2kHz
T1TCR=1; //Counter Enable
DEBUG_PUTS("TX: Configure DMA.\r\n");
DMACCONFIGURATION=1; //Enable DMA
DMAREQSEL_bit.DMASEL10=1; //Select MAT1.0 for DMA request
DMACC0SRCADDR=(unsigned long)TX_DMA_P;
DMACC0DESTADDR=(unsigned long)(&SSP0DR); //Менять тут
DMACC0CONTROL=TX_DMA_START_VALUE_CTRL; //
DMACC0CONFIGURATION=TX_DMA_START_VALUE_CONF;
}
А на предмет развернуть биты - тут есть хитрость. Если их разворачивать путем перестановки каждого бита по одному - да, будет долго. Но есть хороший способ, примерно такой:
CODE
#define C2P_STAGE(RA,RB,SHIFT,MASK) do{UREG32 t=((RB>>(SHIFT))^RA)&(MASK);RA^=t;RB^=t<<(SHIFT);}while(0)
void C2P(UINT32 *s,UREG l)
{
UREG32 r0,r1,r2,r3,r4,r5,r6,r7;
do
{
r0=s[0];
r1=s[1];
r2=s[2];
r3=s[3];
r4=s[4];
r5=s[5];
r6=s[6];
r7=s[7];
C2P_STAGE(r0,r4,4,0x0F0F0F0F);
C2P_STAGE(r1,r5,4,0x0F0F0F0F);
C2P_STAGE(r2,r6,4,0x0F0F0F0F);
C2P_STAGE(r3,r7,4,0x0F0F0F0F);
C2P_STAGE(r0,r2,2,0x33333333);
C2P_STAGE(r1,r3,2,0x33333333);
C2P_STAGE(r4,r6,2,0x33333333);
C2P_STAGE(r5,r7,2,0x33333333);
C2P_STAGE(r0,r1,1,0x55555555);
C2P_STAGE(r2,r3,1,0x55555555);
C2P_STAGE(r4,r5,1,0x55555555);
C2P_STAGE(r6,r7,1,0x55555555);
*s++=r0;
*s++=r1;
*s++=r2;
*s++=r3;
*s++=r4;
*s++=r5;
*s++=r6;
*s++=r7;
}
while(--l);
}
Собственно, что там происходит:
CODE
Проворот:
Исходная матрица
a0b0c0d0e0f0g0h0
a1b1c1d1e1f1g1h1
a2b2c2d2e2f2g2h2
a3b3c3d3e3f3g3h3
a4b4c4d4e4f4g4h4
a5b5c5d5e5f5g5h5
a6b6c6d6e6f6g6h6
a7b7c7d7e7f7g7h7
Меняем по 4 бита:
T=((R4>>4)^R0)&0x0F0F0F0F;
R0^=T;
R4^=T<<4;
...
e0f0g0h0e4f4g4h4
e1f1g1h1e5f5g5h5
e2f2g2h2e6f6g6h6
e3f3g3h3e7f7g7h7
a0b0c0d0a4b4c4d4
a1b1c1d1a5b5c5d5
a2b2c2d2a6b6c6d6
a3b3c3d3a7b7c7d7
Меняем по два бита
T=((R2>>2)^R0)&0x33333333;
R0^=T;
R2^=T<<2;
g0h0g2h2 g4h4g6h6
g1h1g3h3 g5h5g7h7
e0f0e2f2 e4f4e6f6
e1f1e3f3 e5f5e7f7
c0d0c2d2 c4d4c6d6
c1d1c3d3 c5d5c7d7
a0b0a2b2 a4b4a6b6
a1b1a3b3 a5b5a7b7
Меняем по 1 биту
T=((R1>>1)^R0)&0x55555555;
R0^=T;
R1^=T<<1;
h0h1 h2h3 h4h5 h6h7
g0g1 g2g3 g4g5 g6g7
f0f1 f2f3 f4f5 f6f7
e0e1 e2e3 e4e5 e6e7
d0d1 d2d3 d4d5 d6d7
c0c1 c2c3 c4c5 c6c7
b0b1 b2b3 b4b5 b6b7
a0a1 a2a3 a4a5 a6a7
Описана только работа с одним байтом, а проворачивается сразу 4 в каждом регистре, т.е. за раз - 32 байта.