LINUX.ORG.RU

MSP430F1232 и SPI

 , ,


0

1

Насколько корректен нижеприведённый код для работы с SPI на MSP430F1232?

void setup_spi() {
	P3SEL |= BIT1 | BIT2 | BIT3;
	U0CTL = SWRST | CHAR | SYNC;
	U0TCTL = SSEL1;
	U0BR1 = 0;
	U0BR0 = 2;
	U0MCTL = 0;
	ME2 = USPIE0;
        U0CTL &= ~SWRST;
}

void spi_transfer(uint8_t *tx_buffer, uint8_t *rx_buffer, uint16_t count) {
	while (count--) {
		while ((U0TCTL & TXEPT) == 0);
		U0TXBUF = *tx_buffer;
		tx_buffer++;
		if (rx_buffer) {
			while ((IRFG2 & URXIFG0) == 0);
			*rx_buffer = U0RXBUF;
			rx_buffer++;
		}
	}
}

Пытаюсь общаться с NRF24L01+. И мне нужно знать почему оно не работает. Хочу исключить вариант «кривой код работы с SPI».

★★★★★

Последнее исправление: KivApple (всего исправлений: 1)

С spi сложно работать неправильно - ты тупо пишешь в регистры. А вот с устройством вполне можешь работать неправильно.

Я думаю, имеет смысл сделать след. образом. Взять код для работы с spi из либ под TMS-ы, прочитать даташит под NRF24L01+ и работать с ней так, как написано в даташите.

По твоему коду ничего сказать не могу, т.к. хз что у тебя в глобальных переменных и в каком порядке ты все это вызываешь.

Короче, давай полный код.

aiqu6Ait ★★★★
()
Ответ на: комментарий от aiqu6Ait
#include <stdint.h>
#include <stdbool.h>
#include <msp430.h>

/* Timer */

volatile uint16_t frame_counter;
volatile bool next_frame;

void __attribute__((interrupt(TIMERA0_VECTOR))) TIMERA0_ISR() {
	frame_counter++;
	next_frame = true;
	_BIC_SR_IRQ(LPM0_bits);
}

void setup_timer() {
	TACTL = TASSEL_1 | TACLR;
	CCTL0 |= CCIE;
	CCR0 = 32; // 1024 Hz
	TACTL |= MC_1 | ID_0;
}

void wait_next_frame() {
	while (!next_frame) {
		_BIS_SR(LPM0_bits);
	}
	next_frame = false;
}

/* ADC */

uint16_t adc_data[8];

void setup_adc() {
	ADC10CTL0 = SREF_1 | ADC10SHT_2 | ADC10SR | MSC | REFON | ADC10ON;
	ADC10CTL1 = INCH_7 | ADC10DIV_0 | CONSEQ_1;
	ADC10AE = BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0;
	ADC10DTC1 = 8;
}

void start_adc_conv() {
	ADC10CTL0 &= ~ENC;
	while (ADC10CTL1 & BUSY);
	ADC10SA = (uint16_t)(&adc_data);
	ADC10CTL0 |= ENC + ADC10SC;
}

/* SPI */

void setup_spi() {
	P3SEL |= BIT1 | BIT2 | BIT3;
	ME2 |= USPIE0;
	U0CTL = CHAR | SYNC | MM | SWRST;
	U0TCTL = SSEL1 | STC;
	U0BR1 = 0;
	U0BR0 = 2;
	U0MCTL = 0;
	U0CTL &= ~SWRST;
}

void spi_transfer(uint8_t *tx_buffer, uint8_t *rx_buffer, uint16_t count) {
	while (count--) {
		while ((U0TCTL & TXEPT) == 0);
		U0TXBUF = *tx_buffer;
		tx_buffer++;
		while ((IFG2 & URXIFG0) == 0);
		if (rx_buffer) {
			*rx_buffer = U0RXBUF;
			rx_buffer++;
		}
	}
}

/* NRF24L01 */

void nrf24l01_write_reg(uint8_t reg, uint8_t value) {
	uint8_t tx_buffer[2] = {reg | 0x20, value};
	P1OUT &= ~BIT3;
	__delay_cycles(100);
	spi_transfer(tx_buffer, 0, sizeof(tx_buffer));
	__delay_cycles(100);
	P1OUT |= BIT3;
}

uint8_t nrf24l01_read_reg(uint8_t reg) {
	uint8_t tx_buffer[2] = {reg, 0};
	uint8_t rx_buffer[2];
	P1OUT &= ~BIT3;
	__delay_cycles(100);
	spi_transfer(tx_buffer, rx_buffer, sizeof(tx_buffer));
	__delay_cycles(100);
	P1OUT |= BIT3;
	return rx_buffer[1];
}

void setup_nrf24l01() {
	P1DIR |= BIT3; // CSN
	P1OUT |= BIT3;
	P1DIR |= BIT2; // CE
	P1OUT &= ~BIT2;
	__delay_cycles(100000);
	if (nrf24l01_read_reg(10) != 0xE7) {
		P1OUT |= BIT5;
		while (1);
	}
	nrf24l01_write_reg(0, BIT3 | BIT2 | BIT1);
}

/* Main */

int main(void) {
	WDTCTL = WDTPW | WDTHOLD;
	P1DIR |= BIT5;
	setup_timer();
	setup_adc();
	setup_spi();
	setup_nrf24l01();
	_enable_interrupts();
	// Main loop
	while (1) {
		wait_next_frame();
		start_adc_conv();
		if ((frame_counter & 0x7FF) < 64) {
			P1OUT |= BIT5;
		} else {
			P1OUT &= ~BIT5;
		}
	}
}

Код недописан, пока я просто пытаюсь инициализировать NRF24L01. Для проверки читаю 10-ый регистр. Должно считаться 0xE7. Если нет, то зависаю и включаю светодиод. Иначе программа пойдёт дальше и будет мигать светодиодом.

И... программа не находит NRF24L01. Проверка проходит если заменить 0xE7 на 0. А если отключить NRF24L01 физически, то и эта проверка не пройдёт. Получается, что с радиомодуля читаются нули (без него - читаются наводки). Значит SPI частично работает как надо. Как минимум пины CSN и MISO. Вопрос к пинам MOSI и SCK. Они прозваниваются нормально, так что проблема скорее всего не аппаратная.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

подробно даташиты не читал, но на первый взгляд все норм.

читаются нули

А ты подтяжку MOSI к питанию сделал?

aiqu6Ait ★★★★
()
Ответ на: комментарий от aiqu6Ait

Проблема решена - проблема таки была аппаратная - дорожка, которая соединяла SCK микроконтроллера и NRF24L01 была повреждена.

KivApple ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.