Linux: Solução alternativa de bug I2C Broadcom.

Criado em 20 mar. 2013  ·  73Comentários  ·  Fonte: raspberrypi/linux

O broadcom BCM2835 tem um bug (hardware) no módulo I2C.

O BCM implementa "alongamento do relógio" de uma maneira ruim:

Em vez de garantir um "hightime" mínimo para o relógio, o BCM permite que o relógio I2C funcione internamente e, quando chegar a hora de girar o relógio novamente, ele verifica se o relógio está alto ou não, e se estiver baixo, faz um "alongamento do relógio". No entanto, se apenas alguns nanossegundos antes dessa verificação, o escravo libera o sinal do relógio indicando que está pronto para um novo relógio, o pulso do relógio pode se tornar tão curto quanto 40ns. (é o mais baixo que sou capaz de medir, e é claro que é bastante raro). Com um clock I2C de 100 kHz (10 microssegundos), os "maus" momentos para liberar o clock são separados por 5 microssegundos.

Meus escravos requerem um pulso de clock de pelo menos 500 ns. (que deve ser um fator de dez a menos do que o mestre deve gerar quando for configurado para operação de 100 kHz).

Esse é um bug de hardware sobre o qual não podemos fazer muito no momento. (Dica para o pessoal de hardware: em vez de implementar o alongamento do relógio desta forma: inibir a contagem do contador CLOCKDIV enquanto o relógio permanece baixo. Isso provavelmente aumentará o relógio alguns relógios rápidos em cada ciclo, mas a conformidade com os padrões melhorará substancialmente )

Quando isso ocorrer, o BCM enviará um byte, com um primeiro pulso de clock muito curto. O escravo então não vê o primeiro pulso de clock, então quando no final daquele byte é hora de ACK aquele byte, o escravo ainda está esperando pelo 8º bit. O BCM interpreta isso como um "NAK" e aborta a transferência I2C. No entanto, nesse ponto no tempo, o escravo vê seu 8º pulso de clock e emite um "ACK" (puxa a linha SDA para baixo). Isso, por sua vez, significa que o BCM não pode emitir uma condição "INICIAR" adequada para a próxima transferência.

Solução alternativa de software sugerida para reduzir o impacto desse bug de hardware: Quando uma transferência é abortada devido a um "NAK" para um byte, emita um único ciclo de clock extra antes de STOP para sincronizar o escravo. Isso provavelmente deve ser feito no software.

Isso só acontece no "caminho de erro" quando o escravo não ACK um byte. Talvez seja melhor fazer isso apenas quando NÃO for o primeiro byte em uma transferência, pois o bug não pode acontecer no primeiro byte de uma transferência.

Esta correção de software pertence ao driver? Sim. É um driver para uma peça de hardware que tem um bug. É dever do motorista fazer com que esse hardware com bugs funcione da melhor maneira possível.

Bug

Comentários muito úteis

Olá hmf2015,
Este não é um fórum. Este é um rastreador de bug. Esta lista de comentários discute um bug que não está relacionado aos seus problemas. Discuta seu problema com um fórum ou serviço de ajuda apropriado. Novamente, agradecemos sua pergunta: "Talvez seja a mesma coisa? Talvez minha descrição ajude a resolver esse bug?" mas agora sabemos com certeza que o que você está vendo não está relacionado, por favor, não "polua" mais esta discussão.

Todos 73 comentários

Se uma solução alternativa no driver o fizer funcionar melhor para a maioria dos usuários, certifique-se de que ele deve ser incluído.
Você tem um patch adequado?

Não, ainda não.

1) Ainda não investiguei o driver I2C. Cerca de um ano atrás, eu tinha planos de escrevê-lo sozinho, mas antes de começar, outra pessoa o escreveu. Portanto, alguém que já conhece esse driver pode estar mais bem equipado para fazer isso em um projeto de cinco minutos. Eu levaria pelo menos várias horas para conhecer o motorista.
2) Vale a pena discutir primeiro se você (e talvez outros) concordar que uma correção / solução alternativa é garantida.
3) Eu só queria documentar isso como um "todo", não devemos esquecê-lo ...
4) Talvez alguém sugerisse uma solução alternativa diferente.

Falando sobre soluções alternativas: A solução alternativa também pode ser acionada pela linha SDA ainda estar baixa quando estamos tentando iniciar uma nova transação. Essa é claramente uma situação "problemática".

O caso "dá errado" pode ser raro para casos "normais". Muitas pessoas terão um módulo hardware-i2c no barramento I2C. Na época em que o I2C foi inventado, "10us" pode ter sido um período de tempo "muito curto" para alguns chips lidarem com as solicitações, então o alongamento do clock era necessário. Hoje em dia, qualquer implementação de hardware I2C deve ser capaz de lidar com "I2C rápido" até mais rápido.

Isso se combina com a maneira como os caras do atmel implementaram seus módulos assíncronos. Em vez de ter o módulo executado no relógio fornecido externamente (escravo i2c ou escravo SPI), o módulo ainda funciona no relógio do processador. E ele sincroniza todos os sinais de entrada, passando-os por um monte de filpflops. Bom design de hardware. A alternativa é IMHO melhor: execute o módulo fora do relógio externo e sincronize quando os dados passarem para o outro domínio do relógio (cpu-). Isso permitiria, por exemplo, que o módulo SPI funcionasse a 20 MHz, embora a CPU funcione a apenas 8.

De qualquer forma. Chega de divagações de hardware.

Solução alternativa sugerida: Emita um ciclo de clock extra quando, no início de uma transação, a linha SDA ainda estiver baixa. (deve começar alto para poder emitir uma condição de "início").

Em primeiro lugar, sei pouco sobre I2C. Falei com Gert e outros sobre soluções alternativas.

Existem dois problemas conhecidos com I2C:

  1. O problema de alongamento do relógio que você descreveu
  2. Problema com a máquina de estado I2C ao reiniciar

Para 1, a visão de Gert é que não há uma solução alternativa infalível.
Se o escravo I2C não oferece suporte ao alongamento do relógio, tudo bem.
Se o relógio I2C esticar por um valor limitado, então, reduzir a frequência do relógio I2C pode evitar o problema
Mudar para um driver pouco eficaz para escravos que não caem nos casos anteriores é uma solução alternativa segura.

Não sei se sua proposta vai funcionar. Eu gostaria de saber se isso reduz o problema ou o corrige completamente.

Gert diz que tem uma descrição do bug que tentará e será liberado.

Para 2, no driver GPU I2C, temos alguns códigos que contornam um problema com a máquina de estado:

/***********************************************************
 * Name: i2c_actual_read
 *
 * Arguments:
 *       const I2C_PERIPH_SETUP_T *periph_setup,
         const uint32_t sub_address,
         const uint32_t data_to_read_in_bytes,
         void *data
 *
 * Description: Routine to actually transfer data to the I2C peripheral
 *
 * Returns: int == 0 is success, all other values are failures
 *
 ***********************************************************/
static int32_t i2c_actual_read(  const I2C_PERIPH_SETUP_T *periph_setup,
                                 const I2C_USER_T *user,
                                 const uint32_t sub_address,
                                 const uint32_t read_nbytes,
                                 void *data,
                                 const int using_interrupt)
{
   int32_t rc = -1; /* Fail by default */
   int32_t status = 0;
   int32_t nbytes;

   uint32_t sub;
   uint8_t* read_data = (uint8_t*)data;
   uint32_t data_read = 0;

   if( NULL != periph_setup && NULL != data ) {

      // confirm that the latch is held for this transaction
      assert( i2c_state.periph_latch[ periph_setup->port ] != rtos_latch_unlocked() );

      // -> START
      // -> Slave device address | WRITE
      // <- Ack
      // -> Sub address
      // <- Ack
      // -> Sub address
      // <- Ack
      // -> ReSTART
      // -> Slave device address | READ
      // <- Ack
      // <- Data[0]
      // -> Ack
      // <- Data[1]
      // -> nAck
      // -> STOP

      I2CC_x( periph_setup->port )     = I2CC_EN | I2CC_CLEAR; /* Enable I2C and clear FIFO */
      I2CS_x( periph_setup->port )     = I2CS_ERR | I2CS_DONE | I2CS_CLKT; /* clear ERROR and DONE bits */
      I2CA_x( periph_setup->port )     = periph_setup->device_address;

      sub = sub_address;
      nbytes = periph_setup->sub_address_size_in_bytes;

      if( 0 == nbytes ) {
         /* No subaddress to send - just issue the read */
      } else {
         /*
           See i2c.v: The I2C peripheral samples the values for rw_bit and xfer_count in the IDLE state if start is set.

           We want to generate a ReSTART not a STOP at the end of the TX phase. In order to do that we must
           ensure the state machine goes RACK1 -> RACK2 -> SRSTRT1 (not RACK1 -> RACK2 -> SSTOP1). 

           So, in the RACK2 state when (TX) xfer_count==0 we must therefore have already set, ready to be sampled:
           READ ; rw_bit     <= I2CC bit 0   -- must be "read"
           ST;    start      <= I2CC bit 7   -- must be "Go" in order to not issue STOP
           DLEN;  xfer_count <= I2CDLEN      -- must be equal to our read amount

           The plan to do this is:
           1. Start the sub-add]ress write, but don't let it finish (keep xfer_count > 0)
           2. Populate READ, DLEN and ST in preparation for ReSTART read sequence
           3. Let TX finish (write the rest of the data)
           4. Read back data as it arrives

         */
         assert( nbytes <= 16 );
         I2CDLEN_x( periph_setup->port )  = nbytes;
         I2CC_x( periph_setup->port )    |= I2CC_EN | I2CC_START; /* Begin, latch the WRITE and TX xfer_count values */

         /* Wait for us to leave the idle state */
         while( 0 == ( I2CS_x(periph_setup->port) & (I2CS_TA|I2CS_ERR) ) ) {
            _nop();
         }
      }

      /* Now we can set up the parameters for the read - they don't get considered until the TX xfer_count==0 */
      I2CDLEN_x( periph_setup->port )  = read_nbytes;
      I2CC_x( periph_setup->port )     |= I2CC_EN | I2CC_START | I2CC_READ;

      /* Let the TX complete by providing the sub-address */
      while( nbytes-- ) {
         I2CFIFO_x( periph_setup->port ) = sub & 0xFF; /* No need to check FIFO fullness as sub-address <= 16 bytes long */
         sub >>= 8;
      }

      /* We now care that the transmit portion has completed; the FIFO is shared and we mustn't read out
         any of the data we were planning on writing to the slave! */

      /* Wait for peripheral to get to IDLE or one of the two RX states - this way we *know* TX has completed or hit an error */
      {
         uint32_t state;
         bool_t state_transition_complete;
         bool_t error_detected;
         do { 
            state = (I2CS_x( periph_setup->port ) & 0xf0000000) >> 28;
            state_transition_complete = ((state == 0) || (state == 4) || (state == 5));
            error_detected = (I2CS_x(periph_setup->port) & (I2CS_ERR | I2CS_CLKT)) != 0;
         } while(!state_transition_complete && !error_detected);

         if (error_detected) {
            /* Clean up, and disable I2C */
            I2CC_x( periph_setup->port ) &= ~(I2CC_INTD | I2CC_INTR);
            I2CC_x( periph_setup->port ) &= ~(I2CC_START | I2CC_READ);
            I2CS_x( periph_setup->port ) = I2CS_CLKT | I2CS_ERR | I2CS_DONE;
            I2CC_x( periph_setup->port ) |= I2CC_CLEAR;
            I2CC_x( periph_setup->port ) = 0;
            return -1;
         }
      }

      if (using_interrupt)
      {
         /* Wait for interrupt to complete. */
         i2c_state.active_buffer[periph_setup->port] = data;
         i2c_state.active_buffer_length[periph_setup->port] = read_nbytes;
         i2c_state.active_buffer_offset[periph_setup->port] = 0;
         i2c_state.pending_transfer[periph_setup->port] = I2C_PENDING_TRANSFER_READ;
         RTOS_LATCH_T latch = rtos_latch_locked();
         i2c_state.pending_latch[periph_setup->port] = &latch;

         /* Enable interrupt. */
         I2CC_x( periph_setup->port ) |= I2CC_INTD | I2CC_INTR;

         rtos_latch_get (&latch);

         i2c_state.pending_latch[periph_setup->port] = NULL;
         data_read = i2c_state.active_buffer_offset[periph_setup->port];

         rc = (data_read == read_nbytes) ? 0 : -1;
      }
      else
      {
         uint32_t time_now = 0;

         /* Loop until we've read all our data or failed. */
         while( 0 == ( I2CS_x(periph_setup->port) & (I2CS_TA|I2CS_ERR|I2CS_DONE) ) ) {
            _nop();
         }

         /* Wait for some data to arrive - we should wait, at most, I2C_TIMEOUT_IN_USECS for data to arrive every time we start waiting */
         time_now = i2c_state.systimer_driver->get_time_in_usecs( i2c_state.systimer_handle );
         while( ((i2c_state.systimer_driver->get_time_in_usecs( i2c_state.systimer_handle ) - time_now) < I2C_TIMEOUT_IN_USECS)
                && ( data_read < read_nbytes )
                && !(I2CS_x( periph_setup->port ) & I2CS_ERR) ) 
         {
            if (I2CS_x( periph_setup->port ) & I2CS_RXD) 
            {
               read_data[ data_read ] = I2CFIFO_x( periph_setup->port );
               data_read++;
               time_now = i2c_state.systimer_driver->get_time_in_usecs( i2c_state.systimer_handle  );
            }
         }

         if( (data_read != read_nbytes) /* Did we read all the data we asked for? */
             || ( (read_nbytes - data_read) != I2CDLEN_x( periph_setup->port ) ) /* Has DLEN decremented? */
             || ( 0 != (I2CS_x( periph_setup->port ) & I2CS_ERR) ) ) { /* Are there any errors? */
            rc = -1;
         } else {
            while( I2CS_DONE != (I2CS_x(periph_setup->port) & I2CS_DONE) ); /* Wait for the peripheral */
            rc = 0;
         }
      }

      /* Clean up, and disable I2C */
      I2CC_x( periph_setup->port ) &= ~(I2CC_INTD | I2CC_INTR);
      if(I2CS_x( periph_setup->port ) & I2CS_ERR) {
         //Wait for it to be idle
         while(I2CS_x( periph_setup->port ) & I2CS_TA)
            _nop();
      }
      I2CS_x( periph_setup->port ) = I2CS_ERR | I2CS_DONE;
      //Finally disable the I2C
      I2CC_x( periph_setup->port ) = 0x0;
   }

   if( !user->skip_asserts ) {
      assert( rc >= 0 );
      _nop();
   }

   return rc;
}      

Não tenho certeza se as pessoas estão enfrentando esse problema, mas o conteúdo colado pode ser útil se você estiver.

Não é possível erradicar completamente esse bug de hardware.

Quando isso acontece, o mestre e o escravo discordam sobre o número de ciclos de clock. Portanto, os dados, como interpretados pelo escravo e os dados como o mestre (= raspberry pi = driver / aplicativo) pretendidos, diferem. Você pode estar escrevendo um valor completamente falso em um registro em algum lugar. Muito irritante.

Minha solução alternativa sugerida pelo menos faria com que a próxima transação funcionasse. O impacto seria reduzido pela metade: apenas uma transação fracassou em vez de duas. Isso não eliminaria o problema.

Se o escravo I2C não oferece suporte ao alongamento do relógio, tudo bem.

Se o escravo I2C não requer alongamento do relógio ....

Se o relógio I2C esticar por um valor limitado, então, reduzir a frequência do relógio I2C pode evitar o problema

Sim. Tenho 10 dispositivos "no campo" em um local. Aparentemente a frequência de clock (clock RC) de três dos módulos é diferente de tal forma que eles acabam "feitos" com o clock se esticando exatamente no momento errado. A redução da frequência do clock corrigiu os problemas desses módulos.

Se o atraso de alongamento do relógio NÃO for corrigido, mas, digamos, variar em mais de 5 microssegundos, há uma chance mais ou menos estatística de atingir o problema. No meu caso, o escravo requer 0,25 microssegundos de largura de clock. Portanto, o alongamento do relógio termina em 5% do tempo anterior ao momento de mudança do relógio para o BCM, então as coisas dão errado. Portanto, neste caso, cerca de 1 em 20 transferências poderia dar errado. (as especificações dizem 250 ns mín. para um pulso de clock. Isso na verdade não significa que não será visto se for mais curto. Acho que as chances de ser visto vão linearmente de 100% em> 250 ns a 0% em < 125ns.)

Passei ontem esticando o período de alongamento do relógio de tal forma que ele cairia em torno da marca de 2,5 microssegundos na janela de oportunidade de 5 microssegundos. Se eu tivesse como objetivo o início da janela e meu relógio RC rodasse um pouco mais rápido, eu atingiria o "0", o que acionaria o bug. Se eu mirar em 5, é a mesma coisa. Portanto, agora estou apontando para o meio, longe dos lugares ruins. Mas mude o clock I2C para 80kHz, e BAM, estou apontando certo para o ponto sensível ... (e se não acontecer com 80kHz, vai acontecer com algum valor entre 80 e 100).

Aqui está a descrição de Gert do bug I2C:
https://dl.dropbox.com/u/3669512/2835_I2C%20interface.pdf

Haha! Eu instrumentei minha placa de teste exatamente da mesma maneira. Cortei o rastreamento de SCL e montei um conector de jumper de 0,1 "nele. Embora não esteja medindo, há um jumper normal lá, ou um conector fêmea com um resistor de 100 ohms quando estou.

Não acho que isso aconteça apenas no primeiro relógio. Isso significaria que eu poderia contornar o problema NÃO esticando o clock (como a maioria dos chips I2C de hardware provavelmente fazem) ou fazendo com que o clock esticado durasse pelo menos um ciclo completo.

Eu instrumentei meu código escravo i2c de tal forma que posso fazer com que a extensão do clock mude em incrementos de 0,5 microssegundos. Posso comandá-lo para alterar o alongamento do relógio para XXX em I2C e então ele funciona assim por 50 milissegundos antes de voltar aos valores padrão. (caso não funcione, precisamos que volte a funcionar. Assim, posso escanear rapidamente toda uma gama de valores para essas configurações, monitorando as linhas SDA e SCL com um analisador lógico. Enviando um "atraso de uso XXX" e depois enviar um sting leva 25 milissegundos. Então, incrementar um contador no script e enviar o "próximo atraso" leva o script de shell em cerca de 100 ms. Portanto, posso verificar 100 valores possíveis em cerca de 10 segundos.

Eu tenho visto o bug acontecendo em atrasos mais longos. Portanto, a teoria: "só acontece na primeira" não está correta.

Quanto ao manipulador de interrupções "supereficiente": Sim, também posso fazer isso. A questão é: o recurso de alongamento do clock me permite colocar o código "manipular este byte" na rotina de interrupção e não me preocupar se isso levar alguns microssegundos ou alguns milissegundos. Em teoria, o alongamento do relógio fará com que o mestre espere que eu termine de lidar com esse byte antes de continuar com o próximo. Esse plano foi totalmente destruído com o bug do 2835. Agora, apenas faço o alongamento do relógio parar e espero terminar de lidar com o byte nos 70 microssegundos que se seguem.

Eu tenho que fazer uma "contagem cíclica" para apontar para o meio do meio-relógio de 5 microssegundos para liberar o alongamento do relógio. Se eu tivesse como objetivo o início (para causar um período de clock de 4,9 microssegundos), o relógio do meu escravo poderia estar rodando um pouco mais rápido e fazer com que o bug disparasse meio ciclo mais cedo. Portanto, ambas as extremidades do ciclo de meio-relógio são perigosas, eu tenho que buscar um ciclo de relógio curto, mas válido o suficiente.

A mudança no módulo é IMHO simples: Quando SCL é "dirigido alto" (ou seja, não dirigido de todo), pare o relógio mestre do módulo I2C. Isso tem o efeito colateral de permitir barramentos I2C muito mais longos porque o alongamento automático do clock ocorre quando a capacitância do barramento está acima das especificações.

Obrigado por tentar ajudar, iz8mbw, mas isso não tem nada a ver com esse bug (de hardware).

Eu medi meu clock I2C e ele saiu como 100kHz, o que o driver acha que deveria ser. O driver tem um objeto "fonte de relógio", que consulta a frequência e usa-o. Ainda não instrumentei meu driver para imprimir a frequência.

Apenas para obter informações para as pessoas que querem VER o bug em ação, tenho algumas "provas" na forma de um dump de análise lógica.
Hmm, posso anexar imagens, mas não o despejo binário de LA. Esse está aqui: http://prive.bitwizard.nl/LA_with_bug_scan_50_to_100_microseconds_delay.bin.gz

Na imagem LA_with_bug_shot1.png você verá o curto burst de atividade: "set delay to XXX" então um pequeno burst que tenta escrever alguns 10 bytes, mas é abortado devido a um NACK. À direita, você vê um pacote de 10 bytes adequado. A linha SDA permanece baixa até o próximo burst que está desalinhado (todos os bits são deslocados, e no meu escravo o contador "xth-byte-in-packet" não foi zerado pela condição de início inexistente no início desse pacote .

Na imagem LA_with_bug_shot2.png ampliei a seção onde ocorre o pulso curto. Este é o pulso mais longo que já vi dar errado: 290ns. (acima das especificações de folha de dados para o Atmel!)
LA_with_bug_shot1
LA_with_bug_shot2

Oh, então ISSO é de onde isso veio!

Tenho um projeto que estou tentando controlar com I2C de um pi de framboesa e, honestamente, estou perto de desistir e mudar para um beagleboard ou fazer com que o Pi converse com um FPGA via SPI que faz as coisas do I2C .

Tenho uma placa no correio que deve ser capaz de fazer isso (entrega prevista: amanhã). Conector SPI, conector I2C. Seria um bom projeto tentar com essa placa. Envie-me um e-mail se quiser se manter informado.

Situação atual: Estou vendo um comportamento compatível com o de Gert: "apenas o primeiro ciclo pode dar errado" quando o escravo é um ATMEGA, e estou vendo o bug com força total quando o escravo é um dos meus ATTINYs.

Aqui estão os atrasos que testei:
i2c_delays_atmega
e o pulso SCL mais curto observado durante esta sessão de teste foi de 4,5 microssegundos.

Agora testando com o escravo attiny, os atrasos testados para o ACK são:
i2c_delays_attiny

e a largura mínima de pulso é 41ns (minha resolução de medição):
i2c_delays_attiny2

Ah. Encontrei! Parece que o alongamento do relógio antes do ACK de um byte é "perigoso", mas o alongamento do relógio APÓS o ACK está ok ...

Eu e outros certamente estamos atingindo o problema do início repetido. Eu tenho um hack do espaço do usuário em http://cpansearch.perl.org/src/MDOOTSON/HiPi-0.26/BCM2835.xs em proc hipi_i2c_read_register_rs. Isso parece funcionar para os usuários que relataram tentar ou incorporar o código C (embora sejam apenas 5 pessoas), embora eu não tenha descoberto corretamente como determinar se o estágio TX foi concluído. Acho que preciso aprender a compilar os módulos do kernel e executar os testes existentes no código acima.

Não poderíamos simplesmente forçar o kernel a ignorar o hardware I2C e usar I2C baseado em GPIO bitbanged nos mesmos pinos? Eu acho que a sobrecarga para isso seria mais aceitável do que os bugs no próprio hardware.

Que sobrecarga você espera? O padrão do driver atual é o clock de 100 kHz. Portanto, a leitura de 10 bytes de um sensor intertial i2c leva cerca de 1 ms. Se você bitbang, provavelmente terá ciclos de CPU agitados o tempo todo ....

Minha preferência seria que o driver suportasse opcionalmente bitbanging i2c por meio de um parâmetro de módulo (ou talvez um módulo separado, se for mais conveniente).

Muitos dispositivos não usam alongamento do relógio (ou alongamento do relógio por uma quantidade limitada para funcionar corretamente em velocidade reduzida), portanto, o driver I2C de hardware ainda é preferível nesses casos.

O próprio kernel tem um driver para bitbanged I2C em pinos GPIO, este driver tem uma sobrecarga muito menor do que o bitbangging do espaço do usuário e expõe a mesma API que os drivers I2C de hardware. Minha sugestão seria compilar esse driver e o driver I2C de hardware como módulos e, em seguida, carregar o driver de hardware por padrão.

@Ferroin
Você usa o driver I2C bitbanged no Pi?
Quais opções .config você adicionou para construí-lo? Quaisquer patches de origem?
O que você faz para escolher o driver a ser usado (modprobe? / Dev / devices?)

Não usei o driver no Pi, mas tenho um amigo que o usa com sucesso em um BeagleBoard.
A opção de configuração é I2C_GPIO.
Se tanto isso quanto o driver da broadcom fossem configurados como módulos, escolher o driver seria tão simples quanto carregar o módulo do kernel.
O módulo GPIO precisa de parâmetros para informar quais GPIOs usar como SDA e SCL, não sei quais são os parâmetros, mas com base na fonte não muito bem documentada em dirvers / i2c / busses / i2c-gpio.c, parece que os parâmetros apropriados são 'sda = X scl = Y', onde X e Y são os pinos que você deve usar.

O próprio módulo i2c-gpio não fornece nenhuma maneira de passar parâmetros para ele. Portanto, você precisa de outro módulo que registre os dados da plataforma e configure pelo menos o número do barramento, pinos SDA e SCL. Eu escrevi uma prova de conceito de tal módulo e ele funcionou até mesmo nos pinos 0 e 1, mas sem o i2c-bcm2708 carregado (pcf8574 foi detectado pelo i2cdetect, consegui acionar alguns LEDs com o módulo gpio-pcf857x). Mas depois queimei meu pcf8574 ao trocar os pinos (e não tenho nenhum outro chip i2c agora), então não pude realmente testá-lo. Aqui está o código

@kadamsi
Criar parâmetros de módulo sda_pin / scl_pin pode ser útil. Assim como uma solicitação de pull.
Alguém pode confirmar que isso funciona para eles?

Isso é menos trivial do que parece: ele espera que uma estrutura de dados da plataforma seja passada por completo.

Por outro lado, a plataforma não dita quais GPIOs você usará hoje, então trabalhar para mudá-lo parece razoável. (normalmente os dados da plataforma especificam: "Como está / este / computador conectado".)

@popcornmix
Estou planejando torná-los configuráveis, mas não tive tempo suficiente ontem. Também gostaria que fosse possível criar mais de um ônibus por vez. Talvez de forma dinâmica, como arquivos GPIOS export e unexport sysfs (mas não tenho certeza se é possível cancelar a exportação de forma limpa desse barramento)? Ah, e eu encontrei outro pcf8574 e pude confirmar que funcionou bem também em diferentes pinos GPIO quando resistores pullup externos são usados. Infelizmente, não tenho dispositivos I²C mais sofisticados para testar. Então você está interessado em fornecer esse módulo na árvore do kernel padrão?

@kadamski
Não tenho uma configuração para testar módulos como este. No entanto, qualquer recurso de hardware fornecido pelo chip (como I2C) deve ter drivers de kernel para permitir que mais pessoas os usem. Se o hardware I2C tem bugs que impedem as pessoas de usar certos periféricos, uma alternativa de bitbang parece valer a pena.

Portanto, se você produzir um novo driver que pareça inofensivo para as pessoas que não o utilizam (ou seja, construído como um módulo e não nada até ser carregado), e houver alguma evidência (ou seja, alguns relatórios de confirmação do usuário), ele está funcionando corretamente, então eu estou feliz em aceitar um PR.

O HW foi corrigido no BCM2837 (em RPi 3)?

Meu palpite é: não. Mas provavelmente não tenho tempo para testar isso hoje.

BCM2837 I2C não foi alterado.

Isso é lamentável, mas obrigado pela informação.

isso é muito chato.

Concordo. Alguém tem um link para a errata BCM2837, ou similar, informando que o problema ainda existe? Seria útil quando tivermos de passar as novidades adiante. Ou @ P33M , talvez você possa ser citado como confiável se trabalhar para a Broadcom?

Ele é autoritário, embora não funcione para a Broadcom.

Isso é bom. Mas eu já pesquisei no Google e, além de P33M ser M33P em outro lugar, luto para encontrar um ID que eu possa transmitir de forma útil. O que é bom, mas significa que ele não é uma boa fonte para citar. :-) Portanto, um link de errata seria útil.

@ P33M funciona para Raspberry Pi. Você pode tratar o que ele diz como autoridade.

Não acho que haja uma lista de erratas, provavelmente deveria haver. Eu o deixei
para confirmar sua identidade, ou não!

Em 15 de março de 2016 às 14:30, RalphCorderoy [email protected] escreveu:

Isso é bom. Mas eu já pesquisei, e além de P33M ser M33P
em outro lugar, lute para encontrar uma identificação que eu possa transmitir de forma útil. O que é bom,
mas significa que ele não é uma boa fonte para citar. :-) Então, um link de errata seria
acessível.

-
Você está recebendo isso porque comentou.
Responda a este e-mail diretamente ou visualize-o no GitHub:
https://github.com/raspberrypi/linux/issues/254#issuecomment -196845789

@RalphCorderoy Sou funcionário da Raspberry Pi (trading) Ltd. Minha resposta é confiável.

@ P33M , Ta, basta. Desculpe pelo incômodo.

Isso está afetando um projeto no qual estou trabalhando. Felizmente, tenho controle total sobre o firmware do dispositivo escravo e pude adicionar a solução alternativa de adicionar um atraso de meio período extra (extensão do clock) em minhas respostas, o que evita o mau comportamento.

Uma boa análise do problema pode ser encontrada em advamation.com .

Este é um hardware ruim na implementação I2C da Broadcom ou há ajustes de kernel possíveis para fazer com que o hardware se comporte corretamente?

Acabei de me inscrever neste problema porque também o encontrei com um produto que estou desenvolvendo
que usa i2c entre um AVR e Pi. Agora eu preciso repensar.
Alguém já usou alguma forma confiável de bit banging i2c?

@ mwilliams03 , você pode se interessar por este projeto , no qual estabeleci com sucesso uma comunicação I2C de 100 kHz e 400 kHz entre um Raspberry Pi e um AVR. Eu não estou fazendo barulho, mas sim usando o suporte de hardware I2C e inserindo atrasos em pontos-chave. Descobriu-se que o AVR é ​​lento o suficiente para que a 400 kHz não sejam necessários atrasos extras.

Em particular, aqui estão informações sobre os problemas I2C . Observe também que o módulo TWI do AVR tem um problema que impede as leituras rápidas .

obrigado @ pdg137 , experimentei e na primeira tentativa consegui 1,2 milhões de leituras sem erros e continuando.

@rewolff parece que o problema foi resolvido. Se for esse o caso, feche este problema.

E agora .... adicione um deslocador de nível e 40 cm de cabo de extensão .. Funciona então? Provavelmente, isso causa atraso suficiente no lado "para cima" das formas de onda e, de repente, o bug ataca novamente.

Pelo que eu posso dizer, a broadcom e os funcionários ainda acham que esse bug está restrito aos PRIMEIROS 5 microssegundos (na verdade, meio relógio) após o bit final de um byte. então, apenas adicionar 10 microssegundos irá transportar as coisas para mais dois meios-relógios e não deverá haver problemas. Em meus testes, encontro momentos "ruins" para fazer com que o relógio pare de esticar a cada 5 microssegundos.

Devido à simetria entre SPI e I2C, é mais fácil no meu código AVR se o próximo databyte for "calculado" na interrupção "próximos dados" .... (Eu exponho uma interface onde continuar a ler é permitido, portanto, um buffer de 16 bytes nem sempre é suficiente.).

Não estou convencido.

Estou tendo problemas com SMBus entre um Respberry Pi e um ATMEGA 324PA - isso pode estar relacionado a esse problema? https://stackoverflow.com/questions/39274784/talking-smbus-between-raspberr-pi-and-atmega-324pa-avr-not-clock-stretching

Pelo que eu posso dizer, a broadcom e os funcionários ainda acham que esse bug está restrito aos PRIMEIROS 5 microssegundos (na verdade, meio relógio) após o bit final de um byte.

@rewolff : Eu teria que concordar com os funcionários da Broadcom. Em meus testes, com um Raspberry Pi 3 e 100 kHz I2C (que desacelera para 62 kHz quando a CPU é acelerada), estou obtendo resultados semelhantes aos da animação de advamation.com . Você está obtendo resultados experimentais que diferem daquela animação ou a animação não é suficiente para convencê-lo?

A animação parece boa. No entanto, não está de acordo com a minha experiência. Talvez eu deva configurar um teste. Pode demorar um pouco. Está ocupado com outras coisas.

Mas se fosse esse o caso, simplesmente um "usleep (10)" na minha rotina de interrupção (com alongamento do relógio do hardware) normalmente resolveria o problema e faria com que as coisas não travassem. Tenho certeza de que não foi esse o caso. :-(

@rewolff : No Raspberry Pi 3, eu vi a CPU ser acelerada para 600 MHz, resultando em uma velocidade I2C padrão de 62 kHz. Portanto, você deve dormir por 17 microssegundos no ISR do seu escravo se o ISR começar na borda descendente do SCL. Ou se você acha que o CPU pode ficar afogado abaixo de 600 MHz, durma por mais tempo.

Seria possível incluir o módulo i2c-gpio-param de @kadamski no kernel do Raspberry Pi? Posso confirmar que essa abordagem parece funcionar muito bem para meu aplicativo (software AVR I2C escravo) e é um tanto complicado instalar os cabeçalhos necessários para o kernel do raspberry, então tê-lo disponível seria ótimo.

Também seria uma boa solução para resolver o bug de HW subjacente a todo esse problema.

@onnokort Você quer dizer como a sobreposição i2c-gpio presente nos kernels atuais desde novembro de 2015? https://github.com/raspberrypi/linux/blob/rpi-4.4.y/arch/arm/boot/dts/overlays/i2c-gpio-overlay.dts
Do README para sobreposições:

Name:   i2c-gpio
Info:   Adds support for software i2c controller on gpio pins
Load:   dtoverlay=i2c-gpio,<param>=<val>
Params: i2c_gpio_sda            GPIO used for I2C data (default "23")

        i2c_gpio_scl            GPIO used for I2C clock (default "24")

        i2c_gpio_delay_us       Clock delay in microseconds
                                (default "2" = ~100kHz)

@ 6by9 : Incrível, obrigado, aprendi algo novo hoje. Eu não testei isso ainda, mas, sim, parece exatamente o que eu estava procurando (e encontrado em i2c-gpio-param).

@popcornmix @ 6by9 Isso pode ser fechado? Já estou há muuuuito tempo, e as coisas de param dt da minha leitura parecem ser uma opção decente.

A solução alternativa recomendada para dispositivos que definitivamente não funcionam bem com nosso hardware I2C é usar a sobreposição i2c-gpio, que faz bitbash nos pinos.

Caso contrário, o alongamento do clock na fase ACK de endereço é suportado pelo driver upstream.

Caros todos, hoje testei o BNO055 no pacote GY-955 do Leste Asiático que se comporta muito mal a 100_000 Hz com um Pi 2B (BMC2835). Para os testes, mudei a frequência do barramento I2C de 50_000 para 400_000 Hz e encontrei problemas em 100_000 Hz, mas para 50_000, 85_000, 115_000 e 125_000Hz o código de Adafruit (Adafruit_Python_BNO055) funciona muito bem com a conexão I2C, 150_000 Hz parece ser muito rápido para o BNO055, funciona, mas os valores às vezes estão errados. Confesso que não testei a frequência com um osciloscópio, apenas li o arquivo / sys / class / i2c-adapter / i2c-1 / of_node / clock-frequency, portanto, alguma incerteza fica em aberto. Agora começo a implementar uma interface completa para o BNO055 no ADA.
Facit: O bug de hardware no manuseio do BMC I2C aparece apenas em 100_000 Hz, deve ser confirmado.

Apenas para sua informação, o bug de hardware acontece quando o dispositivo escravo estende o clock e libera a linha SCL após 0,9 a 0,999 períodos de clock I2C. A linha começará a subir, e o hardware pi dirá: Oh, ele não fez alongamento do relógio, então posso fornecer o próximo pulso do relógio puxando a linha do relógio para baixo novamente.

O bug acontece quando o tempo restante no período de clock é suficiente para a linha clk passar o limiar "HIGH" para o framboesa, mas não para os dispositivos escravos OU quando o escravo tem filtragem de ruído e considera um alto durante <x% do ciclo de clock I2C normal uma falha.

Isso não "só acontece em 100 kHz", mas também em muitas outras frequências, exceto que o tempo de resposta do dispositivo escravo deve ter um valor diferente.

Suponha que o clock seja 100kHz, então um ciclo normal seria 5us alto e 5us baixo. Agora suponha que em t = 0 o pi comece o último ciclo do clock puxando a linha do clock para baixo. Em t = 5us, o pi libera o sinal do relógio, mas o escravo ainda está ocupado e mantém o relógio baixo. Em t = 9us, o escravo é concluído e libera o sinal do clock. Em t = 10us, o pi vai olhar para o sinal do relógio e pensar: Ok, nenhum relógio esticando, então continue, e ele puxa o sinal do relógio para baixo novamente. O sinal do clock agora está alto por apenas 1us (um pouco menos devido à capacitância e à constante de tempo dos resistores pullup) e pode não ser visto pelo escravo. Agora, um dispositivo diferente não fica pronto após 9 microssegundos, mas após 10,5. Agora, a 100 kHz, o pi verá "ainda baixo, alongamento do relógio, espere mais 5 microssegundos. Agora, obteremos um pulso de clock de 4,5 microssegundos e tudo vai funcionar. Mas execute este dispositivo a 90 kHz e ele terá problemas. Agora o pi olhará 11 microssegundos desde o início, e o sinal do clock estará alto por menos de um microssegundo -> Problemas.

As pessoas que reclamam sobre isso NÃO são as que têm esses outros dispositivos. Eles funcionam no padrão 100kHz. Mas o bug ainda é muito real e ocorreria nesses dispositivos simplesmente em velocidades de barramento diferentes dos dispositivos que você e eu temos.

Obrigado pela resposta, ela explica muito bem porque consegui uma transferência confiável nas frequências que escolhi:
a 100_000 Hz os problemas aumentam no período de 9 a 9,99 µseg
a 85_000 Hz os problemas começam em 1_000_000 / 85_000 * .9 = 10,59 µsec> 9,99 segundos, portanto, o alongamento do relógio é ignorado, presumo, para todas as frequências menores que 85_000 Hz o ponto inicial dos problemas é superior a 10,59 µseg .
em 115_000 Hz o ciclo do barramento é 1_000_000 / 125_000 = 8,7 µsec <9 µseg, portanto, o aumento do clock é detectado corretamente, para todas as frequências superiores a 115_000 Hz o ciclo do barramento é menor que 8,7 µseg.
Assim, quando tenho problemas, posso calcular a frequência de que preciso.
(Eu li as informações em http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html,
foi anotado 0,5 em vez de 0,9 de um período).

Bem. Depende do que seu escravo detecta como um sinal de clock válido. E quanto atraso o RC em seu ônibus apresenta. No meu caso, o AVR que uso como escravo considera pulsos menores que dois ciclos de clock uma falha. Com um relógio RC interno de 8 MHz (+/- 10% !!!), o pulso precisa ser de pelo menos 250 ns para ser detectado. As especificações I2C requerem 5 microssegundos, portanto, há um fator de 20 "margem" entre o que é oficialmente exigido e o que não funciona mais.

No início, pensei em aumentar o alongamento do clock em meu escravo produz um pouco para dizer 12us. Isso funciona até que a capacitância do barramento adicione atraso suficiente para causar um problema novamente. Portanto, é muito difícil contornar. É chato ter que dizer aos seus clientes para não usarem o i2c padrão de 100kHz.

Desculpe, mas precisei de algum tempo para escrever uma implementação completa e um cenário de teste.
Agradeço todas as informações que você me deu, foi muito útil.
Meu cenário de teste é construído com 2 MEMS (BNO055 empacotado como GY-055, MPU9255 empacotado como MPU-9250/6500, registro WHO_AM_I diz MPU9255) e 1 extensor GPIO PCF 8574 (empacotado PCF 8574).
O relógio I2C no Pi (2b) foi ajustado para 125 kHz, verificado pela leitura de / sys / class / adaptador i2c / i2c-1 / of_node / freqüência do relógio.
Meu código é executado 100 vezes lendo dados do MEMS e gravando dados para PCF com um atraso de 0,1 seg.
Resultado:

  • A inicialização do MEMS foi bem-sucedida.
  • A leitura dos dados MEMS no barramento I2C foi bem-sucedida em todos os ciclos.
  • A gravação de dados no PCF pelo barramento I2C foi bem-sucedida em todos os ciclos.

Portanto, o MEMS e o PCF aceitam um clock maior que o padrão de 100 kHz.
Num ambiente antigo a comunicação com o AVR é ​​feita via linha serial, no meu segundo a comunicação será feita via USB, mas não acabou, na verdade tropecei no barramento I2C problemas causados ​​pelo BNO055, mas acho para o meu ambiente, encontrei uma solução alternativa para um Pi 2b e espero que funcione com um Pi 3 também, esse é o próximo teste. E então tenho que integrar 2 outros MEMS, 1 VL53L0X e 1 BME280, espero que funcione com a nova frequência e a capacitância do barramento aceite todos esses elementos.

Estou brincando com esse problema agora em um RPi 3 Modelo B + e estou vendo resultados diferentes dos descritos no artigo da Advamation. O silício não foi acelerado recentemente, certo?

Resumindo, as coisas parecem funcionar se eu esticar em read-preACK, write-preACK ou write-postACK; a única vez que preciso ter certeza de alongar por muito tempo ou não é ler postACK. Ainda preciso limpar meu experimento antes de dizer algo certo, no entanto.

Primeiro, uma nota sobre terminologia. O artigo da Advamation diz:

Então, I2C com o Raspberry Pi só funciona se
o escravo não usa alongamento de relógio, ou
o escravo estica o relógio apenas no final / diretamente após uma fase I2C-read-ACK (depois de ler ACK / NACK), mas então em mais de 0,5 períodos de clock.

O termo "fase I2C-read-ACK" parece um tanto ambíguo. Se for um comando de leitura I2C (ou seja, o bit R / W̅ pós-endereço está definido), o escravo estaria escrevendo o bit A̅C̅K̅, não lendo, ao contrário do parênteses. Quando digo "read-postACK" aqui, quero dizer que o bit R / W̅ foi definido logo após o endereço (e presumivelmente não alterado pelo protocolo como o SMBus faz), então o escravo acabou de escrever sua resposta A̅C̅K̅.

Como já foi sugerido por aqui, parece que se o RPi detectar que o SCL está sendo mantido baixo por um escravo, ele atrasará seu relógio SCL interno em meio ciclo (5μS). O bug é disparado se o escravo mantém o SCL baixo por _quase_ um meio ciclo. Se isso acontecer, o RPi ainda deixará SCL alto e, em seguida, puxará para baixo imediatamente quando seu relógio SCL disparar. Isso resulta em um pulso de clock runt, que alguns dispositivos podem ver como um pulso enquanto outros não. (Para referência: a especificação I2C implica em um tempo SCL nominal alto de 5μS e estabelece um tempo mínimo de 4,0μS a 100kHz, que é a velocidade padrão da interface I2C do RPi.)

Em meus experimentos, nas fases read-preACK, write-preACK e write-postACK, o RPi garantiria que o tempo máximo de SCL permitido fosse de 4 μS ou mais. Ele parecia disposto a atrasar seu relógio SCL nessas fases. Suspeito que o RPi fez uma amostragem da linha SCL logo depois de liberá-la e, se o SCL ainda estava baixo, ele atrasou o relógio SCL uma meia fase.

No entanto, na fase read-postACK, eu vi que o RPi iria emitir relógios runt (<4μS, frequentemente 2μS ou menos) se a linha SCL fosse mantida baixa por cerca de 6–9μS. Suspeito que, nesta fase, os engenheiros da Broadcom seguem um caminho diferente que tenta tornar menos provável que eles tenham que atrasar uma meia fase em uma linha de alta capacitância. Infelizmente - como vimos - é insuficiente.

Portanto, meu código atual precisa esticar o SCL além de ½ ciclo na fase de leitura-postACK de leituras que podem demorar um pouco (como conversões ADC). Se eu falhar em

Os testes atuais que estou executando usam um PIC16F1619 como dispositivo escravo. O dispositivo escravo usa um loop para esticar o relógio nos comandos de leitura e gravação, tanto pré quanto pós-FACK. O comprimento deste loop mais a sobrecarga varia de 3 μS (menos do que o tempo em que o RPi mantém o SCL baixo) a 90 μS em incrementos de 0,35 μS. Tenho um programa Python no RPi que atribui valores diferentes a dois registradores, depois os lê de volta e declara que os valores de leitura estão corretos. Os valores sendo usados

Piquan,
A Broadcom tem minimizado isso ao proclamar que esse problema só acontece no primeiro trecho do relógio. Não creio que seja esse o caso. Você deve ser capaz de verificar isso. A Advamation parece estar seguindo as declarações da broadcom.

@rewolff Bem, pode haver algo em sua interpretação. Se, por "primeiro alongamento do relógio" eles querem dizer "a primeira vez em um determinado estágio em que o SCL é alongado em mais de uma conversão de relógio", sua descrição é precisa: se você alongar em mais de um ciclo de relógio, então sim: em todos fases, se você alongar por> 0,5 ciclo, você está em boa forma. Pelo menos, nas vagas experiências que fiz até agora; experimentos mais precisos ainda estão por vir.

Estou feliz em conduzir alguns experimentos melhores para demonstrar quando o I2C do RPi pode ou não lidar com alongamentos de clock e obter repros que o BCM pode enviar aos engenheiros.

Infelizmente, há uma rotação de silício muito significativa de que eles precisam para corrigir esse problema; eles precisam não marcar o relógio do divisor SCL quando o SCL é mantido baixo (por uma fonte interna ou externa). Isso provavelmente exigirá uma mudança no nível de silício, o que é caro; a maioria dos ECOs são de nível de metal, o que é ... bem, não é barato, mas muito mais barato que o silício.

Meu principal objetivo aqui é caracterizar os tipos de escravos que iriam e não trabalhariam com o RPi, com algumas evidências experimentais.

Parece que precisamos de dados mais sólidos, como cenários de reprodução, para convencer a Broadcom a reprojetar o controlador I2C. Mesmo com dados sólidos, os engenheiros terão que convencer a administração de que vale a pena revisar o silício para a próxima revisão.

Dito isso, vou dedicar algum tempo ao projeto de cenários reproduzíveis para que os engenheiros do BCM possam ver e testar claramente o problema. No entanto, vou depender dos membros da comunidade aqui para comunicar minhas descobertas à Broadcom; Eu não tenho um canal para eles.

Devo esclarecer algo sobre meu comentário anterior para a comunidade, sobre mudanças de silício vs. metal.

Você sabe como, se você obtiver uma placa da SparkFun ou Adafruit, ela geralmente tem traços que você pode cortar ou soldar para mudar seu comportamento? A maioria das placas I2C tem traços que você pode alterar para alterar o endereço, habilitar ou desabilitar os resistores pull-up, etc.

Os designers de microchip fazem a mesma coisa. Há muitas mudanças que eles podem fazer nas camadas de metal de um microchip, para que não precisem alterar as camadas de silício. Isso porque mudar as camadas de silício é difícil e caro (como mudar o chip em uma placa), enquanto as camadas de metal são muito mais fáceis de mudar (como mudar os traços em uma placa).

Muitas mudanças úteis podem ser feitas nas camadas de metal, porque os designers pensam à frente e fazem conexões de metal (jumpers, essencialmente) que mudam o comportamento de um chip.

Mas se houver uma mudança que eles não planejaram e não conseguirem descobrir como fazer reencaminhando os traços dentro do chip, eles terão que mudar o silício. O silício precisa de muito mais planejamento, verificação e mascaramento, por isso é difícil mudar.

Muitas empresas, se tiverem uma camada de silício “boa o suficiente”, a usarão o máximo possível. Eles reutilizarão algumas partes da camada de silício em várias revisões do chip.

Eu suspeito que é onde o BCM está: eles precisam de boas evidências de que esse bug não pode ser corrigido em drivers ou metal antes que eles possam justificar a reengenharia desta parte da camada de silício do zero.

É extremamente improvável que haja uma reformulação do silício existente apenas para corrigir esse problema (tem $ 1 milhão extra?). No entanto, os futuros chips podem ter uma solução, quem sabe.

Na quarta-feira, 5 de setembro de 2018 às 02:13:19 AM -0700, Joel Ray Holveck escreveu:

Parece que precisamos de dados mais sólidos, como cenários de reprodução, para
convencer a Broadcom a reprojetar o controlador I2C. Mesmo com
dados sólidos, os engenheiros terão que convencer a administração de que
vale a pena revisar o silício para a próxima revisão.

Eles já tiveram seis anos e 3 revisões de silício onde
demonstraram sua decisão: "não vai consertar".

se você alongar por> 0,5 ciclo, estará em boa forma.

Eu penso que não. Cada vez que você libera CLK no "pouco antes do
broadcom olha de novo "período de tempo, você obtém pulsos curtos. Posso facilmente
atrasar a liberação do sinal do relógio em, digamos, 5 microssegundos inúteis para
esteja sempre fora do ciclo de 0,5. Mas isso não funcionou.

Na quarta-feira, 5 de setembro de 2018 às 02:28:53 AM -0700, James Hughes escreveu:

É extremamente improvável que haja uma reformulação do
existente de silício apenas para corrigir esse problema (tem um sobressalente $ 1 milhão?). Futuro
chips podem muito bem ter a correção, no entanto

Eu duvido. Passamos do BCM2835 com bug CONHECIDO para o BCM2836 com
o mesmo bug para o BCM2837 com exatamente o mesmo bug para o BCM2837B0.

Agora, por que você acha que a próxima revisão será diferente?

O BCM tem um mercado-alvo: telefones e dispositivos de TV para esses chips. Dentro
seu mercado-alvo, ninguém está fazendo software-I2C de propósito geral
microcontroladores como AVRs e PICs. eles NÃO vão consertar isso.

É uma pena que esse esforço investigativo seja necessário, por maior que seja. Quando eu perguntei antes por uma errata que cuidasse disso, pensei que não havia nenhuma. Isso mudou agora e há um URL? Idealmente, a Broadcom ajudaria a comunidade descrevendo com precisão a falha e quando ela ocorre, para que soluções alternativas ou avaliações de componentes compatíveis sejam mais fáceis de resolver com confiança. Mesmo na extensão do fragmento de HDL relevante, se eles não quiserem tentar traduzir isso precisamente em uma descrição.

A sugestão de parar o divisor de relógio de meio bit ao permitir o alongamento do relógio é boa. Isso funcionaria.

O problema com isso é que parte do módulo I2C precisaria ser executado em "velocidade de clock total". Agora, o módulo I2C é um bom módulo de baixa potência porque normalmente não funciona mais rápido do que 200kHz.

O principal motivo da minha postagem foi o que eu disse no início da postagem original :

Estou brincando com esse problema agora em um RPi 3 Modelo B + e estou vendo resultados diferentes dos descritos no artigo da Advamation. O silício não foi acelerado recentemente, certo?

Se tivemos mudanças significativas no hardware ou driver I2C após a redação do Advamation de 2013 , e a comunidade sabe como isso pode afetar esse bug, então devo fazer as alterações apropriadas em meus experimentos.

Sei que o problema fundamental está no hardware, mas pelo que sei, alguém pode ter descoberto por experiência que alterar um registro aparentemente não relacionado no driver realmente altera o comportamento desse bug. Também não confirmei se o BCM2837 tem o mesmo módulo I2C que o RPi 2 (a última vez em que pude encontrar uma confirmação definitiva de que o hardware I2C não foi alterado desde que esse problema foi relatado pela primeira vez). Eu também não encontrei nenhuma informação sobre qualquer uma das revisões BCM283x; pelo que sei, pode ter ocorrido uma mudança de metal na era BCM2836.

Não estou interessado em criticar a Broadcom, especulando como eles podem mudar as revisões futuras ou algo assim.

Meu principal objetivo aqui é documentar claramente o comportamento atual; parece que mudou com o tempo. Tenho um objetivo secundário de permitir que futuros usuários reproduzam meus experimentos para ver se os resultados ainda são válidos, ou para fazer melhorias ou testar outras condições. Tenho outro objetivo secundário para permitir que os engenheiros da Broadcom reproduzam os testes facilmente se quiserem. Ambos significam que preciso publicar meus experimentos, o que também ajuda: por causa de minha própria arrogância , se eu estiver publicando meus experimentos, estarei mais direcionado para torná-los rigorosos.

Meu plano experimental atual é usar um PIC16F1619 como implementação do escravo; é rápido e versátil o suficiente para fazer os experimentos de alongamento do relógio, fácil de trabalhar e comum o suficiente para que outros pesquisadores possam reproduzir meus resultados. Se os resultados forem ambíguos, também posso construir um experimento com um FPGA. Posso ver se consigo obter granularidade razoável usando outro Raspberry Pi em uma configuração de bit-bashing como escravo, mas suspeito que precisarei de algo sem um sistema operacional inteiro para fazer testes em tempo real.

Para abordar outras coisas que surgiram:

Desculpe que minha postagem original estava incompleta; Eu postei acidentalmente um primeiro rascunho. Vou deixar como está, já que as alterações que fiz são mínimas.

Não reivindico originalidade na ideia de parar o divisor de clock enquanto SCL era externamente mantido baixo. Eu li isso em outro lugar, mas não me lembro onde; Pensei que fosse de Gert van Loo no segmento de alongamento do relógio I2C em raspberrypi.org , mas não consigo encontrar agora, então devo ter visto isso em outro lugar. Não estou convencido de que isso mudaria o perfil de poder significativamente,

O bloco I2C HW não foi corrigido / alterado, e é improvável que seja, no bcm2835 / 6/7, pois isso exigiria respins do chip que é simplesmente muito caro.

Eu não sei quem são Advamation, mas eles não são transmitidos ao grupo RPF (T), então não posso garantir a exatidão dos artigos.

Caros todos, recebi um fenómeno muito estranho no meu Pi 2B e 3, tento explicar:
quando comecei a implementar o BNO055 no final de junho, usei um Raspbian mais velho (não conheço agora a versão) e obtive muitos endereços I2C inválidos usando i2cdetect. Para isso procurei na net e encontrei este fórum com boas informações. Para isso mudei a frequência I2C conforme descrito acima e todos os fantasmas desaparecem e posso trabalhar. Em meados de agosto, atualizei o Raspbian para acho que raspbi-dev 4.14.62-v7 + e o sistema ficou um pouco instável, mas posso funcionar. De atualização para atualização, o sistema tornou-se mais instável, observou-se vazamentos no cartão SD. Portanto, eu reinstalei o Raspbian via NOOBS (Linux raspbi-dev 4.14.62-v7 + # 1134 SMP Tue Aug 14 17:10:10 BST 2018 armv7l) e esqueci de definir a frequência I2C, mas nenhum fantasma apareceu. Ok, eu não uso microkontroller no barramento, apenas MEMS e GPIO extender, mas acho que há uma solução alternativa no código i2c do Raspbian. Além disso, acho que os vazamentos detectados vieram de uma atualização imperfeita, estou usando o mesmo cartão e nenhum vazamento foi detectado.

@ hmf2015 Esse problema é sobre um problema I2C muito específico. Os problemas com o cartão SD não são causados ​​por este problema I2C. Se o seu cartão SD não estiver funcionando direito, você deve tentar um novo cartão SD. Alguns cartões não são bons e param de funcionar rapidamente. Meu cartão SD parou de funcionar no mês passado e tive que substituí-lo.

Normalmente, os fantasmas I2C não são por causa desse problema. Eles acontecem com mais frequência porque:

  • Você não tem uma boa fonte de alimentação. Eu gosto deste
  • Seus cabos são muito longos. I2C não funciona bem com cabos maiores que 1m.
  • Seus cabos possuem acoplamento capacitivo. Se você tiver os pinos I2C (SCL e SDA) torcidos juntos, isso pode ser um problema. Às vezes, as pessoas usam cabos de par trançado (como cabos Ethernet) que torcem os pinos I2C e isso causa problemas. Se você tiver que usar cabos de par trançado, torça SCL com Vss (terra) e SDA com Vdd (3,3 V). Veja a especificação I2C na seção 7.5.
  • Seu dispositivo I2C tem 5V. O Raspberry Pi faz E / S a 3,3V. Se as tensões forem diferentes, isso pode causar problemas. (O BNO055 precisa de 3,3 V, portanto, se você estiver usando-o com 5 V, você tem um problema.)

Eu disse que estamos falando de um problema específico. Alguns dispositivos podem fazer fantasmas por causa desse problema, mas não muitos dispositivos. Se os dispositivos fazem fantasmas por causa desse problema, eles não fazem muitos fantasmas. Eu acho que seu problema é diferente.

Eu não sei o que você quer dizer quando diz que "notou vazamentos no cartão SD". Esse é um problema importante, mas não é o problema de que falamos neste exemplar da página da web. Esta conversa é sobre um bug específico. Esse bug não afeta os cartões SD.

Não acho que o Raspbian recente mudou o funcionamento do I2C. Achamos que o Raspbian não pode corrigir esse bug. Podemos estar errados. Obrigado por nos contar sobre isso.

Se você está apenas nos fornecendo essas informações para nos ajudar, agradecemos. Se você está nos dizendo essas informações para pedir ajuda, você pode pedir nos fóruns do Raspberry Pi . Os fóruns falam sobre muitas coisas, como I2C, cartões SD, extensores GPIO e muito mais. As coisas que você está vendo podem ser as mesmas coisas das quais estamos falando, mas podem ser coisas diferentes. As pessoas nos fóruns podem ajudá-lo a saber quais problemas você está vendo.

Obrigado por nos dizer esta informação!

Obrigado pela resposta, mas o problema do cartão SD foi produzido pelo O / S, eu verifiquei o cartão no meu host (Unix) e estava tudo bem, e agora o mesmo cad funciona perfekt após uma nova instalação.
Os fantasmas no barramento I2C desaparecem por uma frequência mais alta e agora após a reinstalação eles não aparecem, problemas de R / C e reflexos posso, eu acho, excluir. Eu conheço os problemas de 3,3 V, mas o nível mínimo 1 é menor.
O pacote BNO055 possui um regulador de tensão.
Eu também pensei que os problemas I2C seriam os mesmos de antes, mas não, no momento eu não tenho tempo (e interesse) para olhar o código-fonte do Raspbian para detectar as diferenças, estou interessado em um ambiente de trabalho.
A lista de elementos deve apenas mostrar que estou trabalhando em um ambiente Andoid (com um Unix real) como o BCM suporta, não com um microcontrolador que anexo via linha serial ou USB porque sou preguiçoso. No seu ambiente as condições são mais restritas do que as minhas, então não posso dizer se seus problemas diminuem, mas espero.

Olá hmf2015,
Este não é um fórum. Este é um rastreador de bug. Esta lista de comentários discute um bug que não está relacionado aos seus problemas. Discuta seu problema com um fórum ou serviço de ajuda apropriado. Novamente, agradecemos sua pergunta: "Talvez seja a mesma coisa? Talvez minha descrição ajude a resolver esse bug?" mas agora sabemos com certeza que o que você está vendo não está relacionado, por favor, não "polua" mais esta discussão.

@popcornmix
oi, há muito tempo você mencionou um problema com a máquina de estado I2C durante a reinicialização e postou algum código sobre esse problema.
Não tenho certeza do que você quis dizer, mas tenho um problema com o codec WM8731 conectado a I2C.
Após 2-3 reinicializações, o barramento I2C desliga completamente. i2cdetect não mostra nenhuma informação exceto a 1ª linha e desliga também. A única maneira de recuperar é o ciclo de desligamento / aumento de energia.
Parece um problema que você mencionou?
Estou usando o kernel principal 4.19.

@ sergey-suloev Quando i2cdetect não continua a varredura após 8 ou 16 endereços, eu diria que isso não está relacionado a este problema. O problema surge quando os dispositivos aumentam o clock para indicar que ainda não estão prontos para o próximo ciclo do clock. Quando o I2C foi projetado há quase 40 anos, isso também poderia ser concebível para implementações de hardware. Mas hoje em dia, o hardware está sempre pronto para lidar com o próximo ciclo de clock porque 10 microssegundos é uma eternidade para algo implementado no hardware.

Esta página foi útil?
0 / 5 - 0 avaliações